首页 > 代码库 > @selector

@selector

@selector 是什么?

1一种类型 SEL
2代表你要发送的消息(方法), 跟字符串有点像, 也可以互转.: NSSelectorFromString()   /   NSSelectorFromString()

3可以理解为类似函数指针的东西--是能让Objective-C动态调用方法的玩意.--是 object-c 的动态后绑定技术 可以通过字符串 访问的函数指针
4其实就是消息响应函数---选一个消息响应的函数地址给你的action
5@selector(function_name) 即取得一个function的id

objc_msgxxx 系列函数是全局的
performSelector 是NSObject成员方法,ms效果差不多

关于objc_msgSend & performSelector系列函数的问题。

1。objc_msgSend:
书上说这个函数是OC编译器在编译的时候,遇到类似[object foo]的写法时,就会把相应OC的语法转成C的objc_msgSend函数了。还有相应的objc_msgSendSuper


2。关于performSelector系列:
performSelector, performSelector:withDelay:, performSelector:withObj:withDelay, XXX...
除了第一个,后面几个都可以指定一个延迟时间,然后就把selector放到当前线程的runloop中等待调用。从方法名上看,感觉performSelector == performSelector:withDelay系列中,delay为0的情况。


我的问题是:
1。objc_msgSend这个函数是直接由[object foo]转过来的吗? 也就是说,中间不会转成performSelector吧?objc_msgSend是同步的吗?
2。performSelector:withDelay:这个是异步的了,放进runloop中,那如果performSelector和performSelector:withDelay(delay为0时)一样的话, 那performSelector也是异步的吗?也要进runloop吗?


刚开始看cocoa,有很多不懂的。

 

tianya 2011-05-11 08:13
答:
1、是的,不要performSelector了,直接objc_msgSend。事实上,这个是OC编译时就转好的,也就是OC编译的时候就把对象调用转成函数的call了
2、是的,delay为0也进runloop,这样做的好处是可以不阻住当前调用performSelector:withDelay:的方法的执行

怎样证实上边的答案没有问题?
很简单,写几个测试代码,然后打断点一跑,在运行时看调用栈。
观察程序运行最好的方法总是调试器~

respondsToSelector

3、delegate属性使用assign的原因。

循环引用

所有的引用计数系统,都存在循环应用的问题。例如下面的引用关系:

对象a创建并引用到了对象b.

对象b创建并引用到了对象c.

对象c创建并引用到了对象b.

这时候b和c的引用计数分别是2和1。当a不再使用b,调用release释放对b的所有权,因为c还引用了b,所以b的引用计数为1,b不会被释放。b不释放,c的引用计数就是1,c也不会被释放。从此,b和c永远留在内存中。

这种情况,必须打断循环引用,通过其他规则来维护引用关系。比如,我们常见的delegate往往是assign方式的属性而不是retain方式的属性,赋值不会增加引用计数,就是为了防止delegation两端产生不必要的循环引用。如果一个UITableViewController 对象a通过retain获取了UITableView对象b的所有权,这个UITableView对象b的delegate又是a,如果这个delegate是retain方式的,那基本上就没有机会释放这两个对象了。自己在设计使用delegate模式时,也要注意这点。

因为循环引用而产生的内存泄露也是Instrument无法发现的,所以要特别小心。

4、delegate属性使用assign的原因。

还有一些用法会让系统拥有对象的所有权。比如NSObject 的performSelector:withObject:afterDelay 。如果有必要,需要显示的调用cancelPreviousPerformRequestsWithTarget:selector:object: ,否则有可能产生内存泄露。

 

iPhone开发中,动态调用类和方法:

NSClassFromString

NSSelectorFromString

 

正常来说,

id myObj = [[NSClassFromString(@"MySpecialClass") alloc] init];

id myObj = [[MySpecialClass alloc] init];

是一样的。但是,如果你的程序中并不存在MySpecialClass这个类,下面的写法会出错,而上面的写法只是返回一个空对象而已。

因此,在某些情况下,可以使用NSClassFromString来进行你不确定的类的初始化。

比如在iPhone中,NSTask可能就会出现这种情况,所以在你需要使用NSTask时,最好使用:

[[NSClassFromString(@"NSTask") .....]]

而不要直接使用[NSTask ...]这种写法。

NSClassFromString的好处是:

1 弱化连接,因此并不会把没有的Framework也link到程序中。

2 不需要使用import,因为类是动态加载的,只要存在就可以加载。

 

for (int c=0; c<[classNames count]; c++) {

NSString *className=[classNames objectAtIndex:c];

id class=[[NSClassFromString(className) alloc] init];

for (int i=0; i<[params count]; i++) {

[class performSelector:NSSelectorFromString([NSString stringWithFormat:@"setA%i",i])];

}

}