开发过程中会遇到不少小问题,解决的办法有的仅仅是一句话或是一个小的知识点,根本无法凑起一篇博文,因此,在此开出《iOS开发的tips》系列博文,仅为了记录开发中的“灵光一闪”,博文标题以数字标记(1)(2)(3)....,每篇20条,会持续更新....


1、问题:在一个类中(CustomView)声明一个协议:

@protocol CustomViewDelegate
- (void)showActionSheet;
@end

也定义了一个代理:

@property (nonatomic,strong) id<CustomViewDelegate> delegate;

但是在使用代理是出错:

if([dele respondsToSelector:@selector(showActionSheet)]){...}

错误:

No known instance method for selector 'respondsToSelector:'

原因:声明的协议CustomViewDelegate未继承<NSObject>



2、问题:Exec_Bad_Access

一般原因是向已经dealloc的对象发送消息,基于这种原因可以使用NSZombieEnabled进行调试定位。步骤如下:

(1)

wKiom1W8vLmS_k2OAAGAnHA1JKo227.jpg



(2)

wKioL1W8wHjg1Y_UAAGZxVG6xnU261.jpg

这样一来,任何被释放掉得object都会成为一个_ NSZombie,当向_NSZombie发送消息时,会打印出相应的错误信息,而不会Crash或出现奇怪的行为。

注意:调试完后,记得将之前的设置复原,即取消NSZombieEnabled,否则所有的对象是不会被释放的



3、问题:UIActionSheet使用initWithTitle:delegate:cancelButtonTitle:destructiveButtonTitle:otherButtonTitles函数进行初始化的时候出现“Exec_BAD_ACCESS”错误。即使用如下代码会报错:

sheet=[[UIActionSheet alloc] initWithTitle:nil
                                  delegate:nil
                         cancelButtonTitle:@"Cancel"
                    destructiveButtonTitle:@"Destructive"
                         otherButtonTitles:@"aaa",@"bbb","ccc", nil];

原因:网上查了下没有找到具体原因,只是有人说UIActionSheet在iOS8废弃掉了,要使用UIAlertController,设置其preferredStyle为UIAlertControllerStyleActionSheet。



4、ActionSheet和AlertView中的destructiveButton指的是“警示按钮”,显示样式为红色



5、将某些函数调用由异步改为同步,可使用CFRunLoop(NSRunLoop)方法。详见唐巧的技术博客:

http://www.devtang.com/blog/2012/06/24/enhance-uiactionsheet/



6、遍历NSArray的方式(相对应的NSDictionary也有类似的三种方式):

(1)索引

NSArray *arr=@[@"a",@"b",@"c"];
for(int i=0;i<arr.count,++i){
......
}

(2)元素值

NSArray *arr=@[@"a",@"b",@"c"];
for(NSString *s in arr){
......
}

(3)使用Block(OC的新特性)

[arr enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
    ......
}];



对于NSDictionary有

[dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
......
}];


7、Brew工具的安装

        Brew也叫Homebrew,是mac的一种软件管理工具,方便软件的安装和卸载。安装命令如下:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"


8、让XCode的 Stack Trace信息可读。详见唐巧的技术博客:

http://www.devtang.com/blog/2012/11/14/make-stack-trace-more-readable/


9、用脚本来简化iOS美术同学的工作。详见唐巧的技术博客:

http://www.devtang.com/blog/2012/08/26/use-script-to-power-up-ui-work/



10、问题:用真机调试时,Xcode无法和手机联通,出现“iphone(deployment target)”,主要原因是Xcode中设置的target ios版本过高导致的,例如,target ios8.4,而用于调试的手机ios系统版本仅为8.0就会出现无法联通的情况。


11、ios中软键盘的高度有两种:216(纯英文键盘)和252(中文键盘)。一般来讲,键盘的弹起首先默认是英文键盘,之后系统会根据实际情况切换为对应语言的键盘,但由于切换的较快,用户无法察觉。但如果用户开发与键盘高度相关功能的时候,比如输入框高度根据键盘高度变化,那么就会出现输入框高度闪动的情况。这种情况下,可以通过输入法类型来事先判断键盘的最终高度,从而一次性的设置输入框的高度,这样在语言切换的时候就不会有闪动情况了。代码如下:

if([[[UITextInputMode currentInputMode] primaryLanguage] isEqualToString:@"zh-Hans"]){
        height = 252;
    }


12、OC中定义一个类如下:

@interface MyClass:NSObject
@property (nonatomic,strong,readonly) NSString *name;
@end

MyClass包含一个@property name,读写属性为readonly。一般来讲,name初始化后将不再允许更改其值,而且编译器将值生成getter方法。但是,如果另外又定义了setter方法如下:

MyClass.h:

@interface MyClass:NSObject
@property (nonatomic,strong,readonly) NSString *name;
- (void)setName:(NSString *)name;
@end

MyClass.m:
@implementation MyClass
- (void)setName:(NSString *)name{
    _name=name;
}
@end

那么其实name的读写属性又变成了readwrite,可以编译通过。


13、OC中的retain和Copy:

retain是指针拷贝,Copy是内容拷贝。

Copy也分深拷贝和浅拷贝(相当于retain):在Objective-C里只有一种情况是浅拷贝,那就是不可变对象的copy,其它的都是深拷贝(包括不可变对象mutableCopy、可变对象的copy和mutableCopy)。


14、_autoreleasing:用来修饰一个函数的参数,这个参数会在函数返回的时候被自动释放.

id *obj == id __autoreleasing * obj;
NSObject **obj == NSObject * __autoreleasing * obj;



15、(引自唐巧的技术博客)苹果从iOS5开始,引入了新的图象类CIImage。CIImage相比以前的UIImage类,更加适合于图象处理和图象分析。在图象处理方法,苹果内置了CIFilter类,方便开发者对图形进行各种各样的特效处理。

这些内置的Filter在分类上,包括:

  1. 颜色效果类。例如黄昏效果,曝光度调整等。

  2. 组合效果类。把2张图片按各种规则混合成一张图。

  3. 几何变形类。例如把照片倾斜或者翻转。

  4. 重复效果类。如平铺,折叠,镜象等。

  5. 失真扭曲类。如把图片中心做成漩涡效果等。

  6. 模糊和锐化类。

  7. Stylize效果。

  8. Halftone效果。

以上所有效果可以叠加作用在一起,最终你可以创造出自己的图片处理效果。最终你可以通过CIContext,将处理过的CIImage转换成UIImage输出。有了Core Image,你可以方便地开发图象处理相关的应用,而不用关心图象处理算法的细节。


16、设置应用内系统控件的语言,例如app语言为中文,而长按出现的UIMenuController显示的为“select/selectAll”等英文。主要原因是本地化问题。解决方法就是用文本编辑器打开info.plist,然后添加如下代码:

<dict>
......
   <key>CFBundleLocalizations</key>
   <array>
           <string>zh_CN</string>
           <string>en</string>
   </array>
</dict>

这样本地化属性就设置好了,使用的时候控件显示的就会是中文了。

17、Mac隐藏和显示所有文件的命令行指令:

显示:defaults write com.apple.finder AppleShowAllFiles YES

隐藏:defaults write com.apple.finder AppleShowAllFiles NO

18、ios获取沙箱目录路径

(1)获取Documents目录路径:

NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES
);
NSString *documentsPath=[paths objectAtIndex:0];

Documents路径打印出得结果:

/Users/layne/Library/Developer/CoreSimulator/Devices/2548779A-0403-485B-96F9-4695AC5424AD/data/Containers/Data/Application/73F61E0D-A255-4FAF-BD64-CEEA4BE209C7/Documents

(2)获得沙箱的根目录路径

NSString *homeDir=NSHomeDirectory();

沙箱的根目录打印路径:

/Users/layne/Library/Developer/CoreSimulator/Devices/2548779A-0403-485B-96F9-4695AC5424AD/data/Containers/Data/Application/73F61E0D-A255-4FAF-BD64-CEEA4BE209C7

        比较可知,(1)是(2)的下级目录。一般在(2)的目录下有三个文件夹Documents、Library和tmp。

Documents:存放应用程序的数据,一般持久化数据存在这里。

Library:包含Caches和Preferences文件夹,Caches与Documents类似,Preferences与存放应用程序偏好设置。

tmp:存放应用程序临时文件。

(3)获得tmp文件路径:

NSString *tmpDir=NSTemporaryDirectory();

打印结果:

/Users/layne/Library/Developer/CoreSimulator/Devices/2548779A-0403-485B-96F9-4695AC5424AD/data/Containers/Data/Application/29B45D5F-DDA9-4E51-A447-12EFB01A6565/tmp/

19、从属性列表中获得数据时用的函数:

+ (instancetype)stringWithContentsOfFile:(NSString *)path usedEncoding:(NSStringEncoding *)enc error:(NSError **)error;

注意第二个参数usedEncoding:(NSStringEncoding *)enc为指针类型,而NSStringEncoding为枚举类型,因此不能直接赋值,需要进行处理如下:

NSUInteger codingType=NSUTF8StringEncoding;
NSString *m=[NSString stringWithContentsOfFile:filePath usedEncoding:&codingType error:nil];

将codingType取地址之后再作为参数传入。

20、获得一个对象实例的类名:

NSMutableString *s1=[[NSMutableString alloc] init];
NSString *s2=[[NSString alloc] init];
NSLog(@"%@",NSStringFromClass([s1 class]));//结果:__NSCFString
NSLog(@"%@",NSStringFromClass([s2 class]));//结果:__NSCFConstantString