iOS開發中@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效果差不多
Objective-C的動態後綁定技術:可以通過字串訪問的函數指標
typedef obj_handler * SEL;
關於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嗎。
答:
1、是的,不要performSelector了,直接objc_msgSend。事實上,這個是OC編譯時間就轉好的,也就是OC編譯的時候就把對象調用轉成函數的call了
2、是的,delay為0也進runloop,這樣做的好處是可以不阻住當前調用performSelector:withDelay:的方法的執行
怎樣證實上邊的答案沒有問題。
很簡單,寫幾個測試代碼,然後打斷點一跑,在運行時看調用棧。
觀察程式運行最好的方法總是調試器~
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這個類,下面的寫法會出錯,而上面的寫法只是返回一個Null 物件而已。
因此,在某些情況下,可以使用NSClassFromString來進行你不確定的類的初始化。
比如在iPhone中,NSTask可能就會出現這種情況,所以在你需要使用NSTask時,最好使用:
[[NSClassFromString(@"NSTask") .....]]
而不要直接使用[NSTask ...]這種寫法。
NSClassFromString的好處是:
1 弱化串連,因此並不會把沒有的Framework也link到程式中。
2 不需要使用import,因為類是動態載入的,只要存在就可以載入。
@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這個類,下面的寫法會出錯,而上面的寫法只是返回一個Null 物件而已。
因此,在某些情況下,可以使用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])];
}
}