注意事项
NSKeyedArchiver 自定义对象写文件
如果存储的对象类名有变动,则需要设置clasName, 方法为:“setClassName:forClass:”
使用 NSKeyedArchiver 进行数据持久化时, 系统会默认使用类名去建表,如果类名变了,那么使用新的类名肯定是从本地获取不到表的,代码执行崩溃。
所以需要在 NSKeyedArchiver 或者 NSKeyedUnarchiver 时使用 “setClassName:forClass:” 指定类名。
断点配置:【Generate Debug Symbols】
描述: 用来控制断点是否生效,关闭此功能,打包 .ipa
时,包体积会小很多。
配置路径:【project/TARGETS/Build Settings/Apple LLVM7.1 - Code Genneration/Generate Debug Symbols】
捕获全局异常:【All Exception】
描述: 用来捕捉整个项目在 Xcode 里执行时的异常。例如:try/catch 时 catch住的异常,【All Exception】可以直接定位到具体位置。
配置路径: 异常捕捉(commod+7)/Xcode左下角点击+/Add Exception Breakpoint/完成(回车键)
UI相关
1、设置状态栏颜色:
info.plist 添加 View controller-based status bar appearance - NO
代码里写 [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent]; 再次运行后状态栏就会变成白色。
2、左滑返回手势失效了怎么办:
设置 navigationItem.leftBarButtonItem 之后,左滑返回手势就会失效。设置一下 UIGestureRecognizerDelegate 代理即可:
self.navigationController.interactivePopGestureRecognizer.delegate = self;
3、让 TableView的 下拉 和 上拉 显示不一样的背景颜色:
给 TableView 上加一个 View,View 的 Frema:
CGRectMake(0, -self.view.bounds.size.height, self.view.bounds.size.width, self.view.bounds.size.height + 2),
给变View的背景颜色就可以了。
block 的注意事项
(1)block 在实现时就会对它引用到的它所在方法中定义的栈变量进行一次只读拷贝,然后在 block 块内使用该只读拷贝。
(2)非内联(inline) block 不能直接访问 self,只能通过将 self 当作参数传递到 block 中才能使用,并且此时的 self 只能通过 setter 或 getter 方法访问其属性,不能使用句点式方法。但内联 block 不受此限制。
(3)使用 weak–strong dance 技术来避免循环引用
(4)block 内存管理分析
block 其实也是一个 NSObject 对象,并且在大多数情况下,block 是分配在栈上面的,只有当 block 被定义为全局变量或 block 块中没有引用任何 automatic 变量时,block 才分配在全局数据段上。 __block 变量也是分配在栈上面的。在 ARC 下,编译器会自动检测为我们处理了 block 的大部分内存管理,但当将 block 当作方法参数时候,编译器不会自动检测,需要我们手动拷贝该 block 对象。
在 ARC 下,对 block 变量进行 copy 始终是安全的,无论它是在栈上,还是全局数据段,还是已经拷贝到堆上。对栈上的 block 进行 copy 是将它拷贝到堆上;对全局数据段中的 block 进行 copy 不会有任何作用;对堆上的 block 进行 copy 只是增加它的引用记数。
如果栈上的 block 中引用了__block 类型的变量,在将该 block 拷贝到堆上时也会将 __block 变量拷贝到堆上如果该 __block 变量在堆上还没有对应的拷贝的话,否则就增加堆上对应的拷贝的引用记数。
block 基本演练
1 最简单的 block
- (void)blockDemo1 {
// 定义block
// 类型 变量名 = 值
void (^block)() = ^ {
NSLog(@"Hello block");
};
// 执行
block();
}
tip :使用 inlineBlock 可以快速定义 block.
- 当作参数传递
- (void)blockDemo2 {
void (^block)() = ^ {
NSLog(@"Hello block");
};
[self demoBlock:block];
}
/// 演示 block 当作参数传递
- (void)demoBlock:(void (^)())completion {
NSLog(@"干点什么");
completion();
}
- 使用局部变量
- (void)blockDemo3 {
// 栈区变量
int i = 10;
NSLog(@"%p", &i);
void (^block)() = ^ {
// 定义 block 的时候会对栈区变量进行一次 copy
NSLog(@"Hello block %d %p", i, &i);
};
[self demoBlock:block];
}
如果 block 中使用了外部变量,会对外部变量做一次 copy
- 在 block 中修改外部变量
- (void)blockDemo4 {
// 栈区变量
__block int i = 10;
NSLog(@"%p", &i);
void (^block)() = ^ {
// 定义 block 的时候会对栈区变量进行一次 copy
NSLog(@"Hello block %d %p", i, &i);
i = 20;
};
NSLog(@"block 定义完成 %p %d", &i, i);
[self demoBlock:block];
NSLog(@"===>%d", i);
}
如果要在 block 内部修改栈区变量,需要使用 __block 修饰符,并且定义 block 之后,栈区变量的地址会变化为堆区地址
block 的内存位置
- 全局区:如果block中没有使用任何全局变量
- 栈区:如果 block 中使用了外部变量
MRC 模式可以看到
ARC 模式,系统会自动将 Block 复制到堆中
- 堆区:将 block 设置给 copy 属性
@property (nonatomic, copy) void (^myBlock)();
- (void)blockDemo5 {
int i = 10;
void (^block)() = ^ {
NSLog(@"i --- %d", i);
};
NSLog(@"%@", block);
self.myBlock = block;
}
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
NSLog(@"%@", self.myBlock);
}
注意:虽然目前 ARC 编译器在设置属性时,已经替程序员复制了 block,但是定义 block时,仍然建议使用 copy 属性