用法小知识点

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中的集合运算符如何使用?

  1. 必须用在集合对象上或普通对象的集合属性上

  2. 简单集合运算符有@avg, @count , @max , @min ,@sum,

  3. 格式 @"@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 程序中,同样有效!

9、Autorelease Pool

自动释放池以栈的形式实现: 当你创建一个新的自动释放池时,它将被添加到栈顶。接收autorelease消息的对象将被放入到最顶端的自动释放池中。

a、主线程:
在每一个事件周期(event cycle)的开始,系统会自动创建一个自动释放池;在每一个事件周期的结尾,系统会自动销毁这个自动释放池。一般情况下,你可以理解为:当你的代码在持续运行时,自动释放池是不会被销毁的,这段时间内你也可以安全地使用自动释放的对象;当你的代码运行告一段落,开始等待用户输入(或者其它事件)时,自动释放池就会被释放掉,池中的对象都会收到一个release消息,有的可能会因此被销毁。
b、其他线程:
手动创建自动释放池。自己负责创建,最后自己负责释放。自动释放池释放时,里面的对象也会释放。

10、imageNamed:方法,得到的图片不需要解码,不过会产生缓存;imageWithContentxOfFile:,得到的图片要在GPU提交时进行解码,没有缓存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值