Objective-C
本质上是一门非常动态的语言(参见第11条),NSObject
定义了几个方法, 令开发者可以随意调用任何方法。这几个方法可以推迟执行方法调用,也可以指定运行方法所用的线程。这些功能原来很有用,但是在出现了GCD
之后,这些功能就尽量不要使用了,尽量用GCD
来取代他们。
其中他们又如下几个方法:
-(id)performSelector : (SEL) selector
//可以传两个参数
-(id)performSelector : (SEL) selector
withObject:(id)objectA
withObject:(id)objectB
//传一个参数
-(id)performSelector : (SEL) selector
withObject:(id)object
具体用法如:
[object performSelector: @selector(selectorName)];
[object performSelector: @selector(setValue:)
withObject: newValue];
上面的用法,会有很多局限,比如在ARC
下,会发出警告表示:也许会内存泄露
,这是因为编译器并不知道将要的选择子是什么,因此,也就不了解其方法签名及返回值,甚至连是否有返回值都不清楚,而且由于编译器不知道方法名,所以就没办法运用ARC
的内存管麵则来判定返回值是不是该释放。鉴于此,ARC
采用了比较谨慎的做法,就是不添加释放操作。然而这么
做可能导致内存泄漏,因为方法在返回对象时可能已经将其保留了。
另一个局限性是:返回值只能是void
或对象类型。尽管所要执行的 选择子也可以返回void
,但是performSelector
方法的返回值类型毕竟是id
。如果想返回整数或浮点数等类型的值,那么就需要执行一些复杂的转换操作了,而这种转换很容易出错。
第三个局限是:这个方法最多只能传递两个参数,当选择子得到参数超过两个时,只能运用字典来传送数据(但是容易增加开销和造成bug)。
所以我们的解决方法是:我们使用块
来代替,并且performSelector
系列方法都可以使用GCD
机制使用块来实现。我们来举几个例子说明:
如果我们想要延后执行某个任务:
//Using performSelector:withObjectrafterDelay:
[self performSelector:@selector(doSomething)
withObject:nil
afterDelay:5.0];
//Using dispatch_after
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64 t)(5.0 * NSEC PER SEC));
dispatch_after(time, dispatch_get_main—queue(), ^(void){
[self doSomething];
});
后者想要在主线程执行某个任务:
// Using performSelectorOnMainThread: withObject .-waitUntilDone :
[self performSelectorOnMainThread:@selector(doSomething)
withObject:nil
waitUntilDone:NO];
//Using dispatch_async
// (or if waitUntilDone is YES, then dispatchasync)
dispatch_async(dispatch_get_main_queue(), ^{
[self doSomething];
});
要点
performSelector
系列方法在内存管理方面容易有疏失。它无法确定将要执行的选择子具体是什么,因而ARC
编译器也就无法插入适当的内存管理方法。performSelector
系列方法所能处理的选择子太过局限了,选择子的返回值类型及发送给方法的参数个数都受到限制。- 如果想把任务放在另一个线程上执行,那么最好不要用
performSelector
系列方法,而是应该把任务封装到块里,然后调用大中枢派发机制的相关方法来实现。