之前看完了<iOS开发进阶>, 也做了相应的总结, 详见:读<iOS开发进阶>有感
今天花点时间, 把一些干货汇总下, 然后就可以和这本书say goodbye了。
包括:
- p85 10.1.3
- p96 使用GCD后
- p99 后台运行
- p131 使用Safari进行调试
- p184 收起键盘
- p185 设置应用内的系统控制语言
- p193 忽略编译警告
- p198 给模拟器相册增加图片
10.1.3 不要向已经释放的对象发送消息
有些读者想测试当对象释放时, 其retainCount 是否变为了0, 他们的试验代码如下: (记得要在Appdelegate.m 中 设置为MRC -fno-objc-arc)
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. NSObject *object = [[NSObject alloc] init]; NSLog(@"Reference Count = %u", [object retainCount]); [object release]; NSLog(@"Reference Count = %u", [object retainCount]); return YES; } // 打印结果 // 2015-01-21 10:04:05.799 MRC_Test[2985:607] Reference Count = 1 // 2015-01-21 10:04:05.800 MRC_Test[2985:607] Reference Count = 1
我们注意到, 最后一次输出, 引用计数没有变成0。因为该对象的内存已经被回收,而我们向一个已经被回收的对象发一个retainCount消息,所以它的输出结果应该是不确定的,如果该对象所占的内存被复用了,那么就有可能造成程序异常崩溃。
那为什么这个对象被回收之后,这个不确定的值是1而不是0呢。这是因为当最后一次执行release时,系统知道马上就要回收内存了。就没有必要再将retainCount减1了,因为不管减不减1,该对象都肯定会被回收。而对象被回收后,它的所有内存区域,包括retainCount值也变得没有意义。不将这个值从1变为0,可以减少一次内存的操作,加速对象的回收。
使用GCD后
11.2.4 后台运行
使用block的另一个用处是可以让程序在后台较长久地运行。
在以前, 当应用被按Home键退出后,应用仅有最多5秒钟的时间做一些保存或清理资源的工作。但是应用可以调用UIApplication 的 beginBackgroundTaskWithExpirationHandler方法,让应用最多有10分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。
// Appdelegate.h
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;
// Appdelegate.m
launchOptions { // Override point for customization after application launch. return YES; } - (void)applicationWillResignActive:(UIApplication *)application { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - (void)applicationDidEnterBackground:(UIApplication *)application { [self beginBackgroundUpdateTask]; //在这里添加需要长久运行的代码 [self endBackgroundUpdateTask]; } - (void)beginBackgroundUpdateTask { self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{ [self endBackgroundUpdateTask]; }]; } - (void)endBackgroundUpdateTask { [[UIApplication sharedApplication] endBackgroundTask:self.backgroundUpdateTask]; self.backgroundUpdateTask = UIBackgroundTaskInvalid; }
15.7 使用Safari进行调试
18.2.2 收起键盘
在UIViewController中收起键盘, 除了调用相应控件的resignFirstResponder 方法外, 还有另外三种办法:
1. 重载 UIViewController 中的 touchesBegin方法, 然后在里面执行 [self.view endEdiiting: YES]; 这样单击UIViewController的任意地方, 就可以收起键盘。
2. 直接执行[[UIApplication sharedApplication] sendAction:@selector(resignFirstResponder) to: nil from: nil forEvent: nil]; 用于在获得当前UIViewController比较困难的时候用。
3. 直接执行 [[[UIApplication sharedApplication] keyWindow] endEditing: YES]
18.2.4 设置应用内的系统控制语言
在iOS应用中, 有时候会需要调用系统的一些UI控件, 例如:
1. 在UIWebView中长按弹出系统的上下文菜单。
2. 在UIImagePickerController中会使用系统的照相机界面。
3. 在编译状态下的UITableViewCell, 处于待删除状态时, 会有一个系统的删除按钮。
以上这些UI控件, 其显示的语言并不是和你当前手机的系统语言一致, 而是根据你的应用内部的语言设置来显示。
在 info.plist文件中, 增加:
CFBundleLocalizations zh_CN
18.2.9 忽略编译警告
使用-w禁止掉所有的编译警告, 用-Wno-unused-variable 只禁止未使用变量的编译警告。
(用法和 -fno-objc-arc 一样)
18.4.3 给模拟器相册增加图片
... 直接把图片拖放到模拟器中, 会利用Safari打开, 然后保存即可。