1、NSTimer 在子线程中应该手动创建NSRunLoop ,否则不能循环执行。
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
timer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(method) userInfo:nil repeats:YES] retain];//一定要retain,不然timerStart执行完后,NSTimer就被释放了。
[runLoop run];
[pool release];
2、BAD_ACCESS在什么情况下出现?
访问了野指针,比如对一个已经释放的对象执行了release、访问已经释放对象的成员变量或者发消息。 死循环
3、以下代码运行结果如何?
1
2
3
4
5
6
7
8
9
|
- (void)viewDidLoad
{
[
super
viewDidLoad];
NSLog(@
"1"
);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@
"2"
);
});
NSLog(@
"3"
);
}
|
只输出:1 。发生主线程锁死。
4、如何手动触发一个value的KVO
所谓的“手动触发”是区别于“自动触发”:
自动触发是指类似这种场景:在注册 KVO 之前设置一个初始值,注册之后,设置一个不一样的值,就可以触发了。
想知道如何手动触发,必须知道自动触发 KVO 的原理:
键值观察通知依赖于 NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey: 。在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就 会记录旧的值。而当改变发生后, didChangeValueForKey: 会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。如果可以手动实现这些调用,就可以实现“手动触发”了。
那么“手动触发”的使用场景是什么?一般我们只在希望能控制“回调的调用时机”时才会这么做。
具体做法如下:
如果这个 value 是 表示时间的 self.now ,那么代码如下:最后两行代码缺一不可。
1
2
3
4
5
6
7
8
9
10
11
12
|
// .m文件
// Created by https://github.com/ChenYilong
// 微博@iOS程序犭袁(http://weibo.com/luohanchenyilong/).
// 手动触发 value 的KVO,最后两行代码缺一不可。
//@property (nonatomic, strong) NSDate *now;
- (void)viewDidLoad
{
[
super
viewDidLoad];
[self willChangeValueForKey:@
"now"
];
// “手动触发self.now的KVO”,必写。
[self didChangeValueForKey:@
"now"
];
// “手动触发self.now的KVO”,必写。
}
|
但是平时我们一般不会这么干,我们都是等系统去“自动触发”。“自动触发”的实现原理:
比如调用 setNow: 时,系统还会以某种方式在中间插入 wilChangeValueForKey: 、 didChangeValueForKey: 和 observeValueForKeyPath:ofObject:change:context: 的调用。
大家可能以为这是因为 setNow: 是合成方法,有时候我们也能看到人们这么写代码:
1
2
3
4
5
|
- (void)setNow:(NSDate *)aDate {
[self willChangeValueForKey:@
"now"
];
// 没有必要
_now = aDate;
[self didChangeValueForKey:@
"now"
];
// 没有必要
}
|
这是完全没有必要的代码,不要这么做,这样的话,KVO代码会被调用两次。KVO在调用存取方法之前总是调用 willChangeValueForKey: ,之后总是调用 didChangeValueForkey: 。怎么做到的呢?答案是通过 isa 混写(isa-swizzling)。下文《apple用什么方式实现对一个对象的KVO?》会有详述。
5、KVC的keyPath中的集合运算符如何使用?
-
必须用在集合对象上或普通对象的集合属性上
-
简单集合运算符有@avg, @count , @max , @min ,@sum,
-
格式 @"@sum.age"或 @"集合属性.@max.age"
6、Xcode 7 已经集成了BAD_ACCESS捕获功能:Address Sanitizer。 用法如下:在配置中勾选?Enable Address Sanitizer
7、watchdog(看门狗)机制
为了防止一个应用占用过多的系统资源,开发iOS的苹果工程师门设计了一个“看门狗”的机制。在不同的场景下,“看门狗”会监测应用的性能。如果超出了该场景所规定的运行时间,“看门狗”就会强制终结这个应用的进程。开发者们在crashlog里面,会看到诸如0x8badf00d
这样的错误代码。
在ARC及手机型号比较低的情况下,这种现象尤为突出。
8、Autorelease
- 在 mrc 的代码中,没有 weak,只有 assign
- assign 修饰符号,对对象不做任何操作,只是简单的记录地址
- weak 是 ARC 专有的,如果对象没有其他任何对象做强引用,会被立即释放!
- weak 的效率非常差!
- assign 会记录住地址,对象释放后,地址仍然保留,在 MRC 开发中,野指针错误非常频繁
- weak 安全性很好!一旦没有强引用,自动将地址设置为 nil,OC中可以向 nil 发送任何消息都不会抱错!
- autorelease 作用就是
延迟释放
,给对象添加延迟释放的标记 -
- 所有 "autorelease" 的对象,在出了作用域之后,会被自动添加到"最近创建的"自动释放池中!
- 在自动释放池被销毁或者耗尽的时候,会向池中所有对象发送 release 消息,释放池中对象
- 自动释放池,在 ARC & MRC 程序中,同样有效!
自动释放池以栈的形式实现: 当你创建一个新的自动释放池时,它将被添加到栈顶。接收autorelease消息的对象将被放入到最顶端的自动释放池中。
a、主线程:
在每一个事件周期(event cycle)的开始,系统会自动创建一个自动释放池;在每一个事件周期的结尾,系统会自动销毁这个自动释放池。一般情况下,你可以理解为:当你的代码在持续运行时,自动释放池是不会被销毁的,这段时间内你也可以安全地使用自动释放的对象;当你的代码运行告一段落,开始等待用户输入(或者其它事件)时,自动释放池就会被释放掉,池中的对象都会收到一个release消息,有的可能会因此被销毁。
b、其他线程:
手动创建自动释放池。自己负责创建,最后自己负责释放。自动释放池释放时,里面的对象也会释放。
10、imageNamed:方法,得到的图片不需要解码,不过会产生缓存;imageWithContentxOfFile:,得到的图片要在GPU提交时进行解码,没有缓存。