黑馬程序員——IOS基礎——OC面向對象六SEL

------- android培訓java培訓、期待與您交流!

=========官方文檔翻譯=========

在OC中,selector有兩層含義。

1、當selector在源代碼中被用來指向一個對象的時候,selector可以僅僅指這個方法的名稱。
2、代碼編譯的時候會生成一個唯一的標示符,selector也可以指向該標示符。

selectors的編譯類型爲SEL。所有有同樣名稱的方法都有同樣的selector。針對某個對象(object),你可以使用selector去調用它的方法。這給Cocoa的目標-行爲設計模式(the target-action design pattern,注:關於這部分在該篇API的最後進行了說明)提供了執行的基礎

Methods and Selectors

爲了提高效率,在編譯規則(compiled code)中一個完整的ASCII名稱不被作爲方法的selectors。取而代之的方法是,編譯器將每一個方法的名稱寫到一個table中,然後跟一個唯一的標示符配對,該標示符在運行過程中會代表一個具體的方法。運行系統(runtime system)確保每一個標示符都是唯一的:沒有兩個selector是相同的,而且所有有同樣名稱的方法有同樣的selector


SEL and @selector

selector編譯後被指定到一種特殊的類型——SEL來與其它類型進行區分。有效的selector永遠不會爲0.你必須讓系統給方法分配SEL標示符,自行任意分配的標示符是無效的。

你應該使用@selector()指令將方法名傳遞給編譯的selector,而不是直接使用一個方法的全名。比如,下面的方法可以獲得setWidth:height: 方法的selector,並且分配給setWidthHeight變量:


SEL setWidthHeight;

setWidthHeight = @selector(setWidth:height:);

最有效的的方式是在編譯的時候調用@selector()指令給SEL變量賦值。但在有些情況下,你可能需要在運行時候將字符串轉換給某個selector。你可以使用NSSelectorFromStringn函數完成這項工作:

setWidthHeight = NSSelectorFromString(aBuffer);

反着轉換也是可行的。NSStringFromSelector函數可以返回某個selector的方法的名稱:


NSString *method;

method = NSStringFromSelector(setWidthHeight);

Methods and Selectors

selector編譯後可以識別方法名稱,但不實現方法(not method implementations)。比如,對於一個類而言,它的display方法和其它同樣定義了display方法的類有相同的selector。對於動態綁定和多態性而言這是必不可少的,它可以讓你給不同類的接收器發送相同的方法。如果每一個執行方法都有一個selector,那麼發送這條信息就跟調用了一個函數回調(function call)沒什麼區別了。

具有相同名稱的類方法和實例方法被分配了相同的selector,單因爲他們屬於不同的領域,這兩者之間也不會產生混淆。一個類能定義display方法,附加給一個實例方法。

Method Return and Parameter Types

通告程序(messaging routine)只能通過selector訪問方法實體(method implementation),所以它用同樣的selector處理所有方法 (注:這句話不理解,附原文so it treats all methods with the same selector alike)。通告程序(it)可以通過selector辨別一個方法的返回類型、以及參數的數據類型。因此,除非通告(message)是發送給靜態類型的接收器,否則對於動態綁定接收器,會要求所有有同樣名稱方法的實例頁有同樣的返回類型和參數類型。(對於該規則,靜態類型的接收器屬於例外的原因是編譯器能從類的類型瞭解該方法實體。)


雖然相同名稱的類方法和實例方法是使用同樣的selector代表的,它們可以有不同的參數類型和返回值類型。


Varying the Message at Runtime


NSObject協議中定義的 performSelector:, performSelector:withObject:,和 performSelector:withObject:withObject:方法使用SEL標示符作爲它們的初始化參數。所有這三個方法(注:我很奇怪爲什麼是三個,但是原文就是寫的三個...)直接映射到通告功能(massaging function)。例如:


[friend performSelector: @selector(gossipAbout:)

withObject: aNeighbor];
相當於

[friend gossipAbout:aNeighbor];

這些方法使應用運行時改變message成爲可能,就像可以改變一個接收message的object一樣。Variable names can be used in both halves of a message expression:

id   helper = getTheReceiver();

SEL  request = getTheSelector();

[helper performSelector:request];

在這個例子中,接收器helper在運行時候進行選擇(通過一個假設的getTheReceiver函數),方法接收器頁要求在運行時執行request(同樣通過一個假設的getTheSelector函數)

Note:performSelector: 方法和它其它同伴的方法都返回一個類型爲id的對象,如果當前執行的方法返回一個不同的類型,它應當被轉換爲適當的類型。(但,轉換不適用於所有類型,方法應當返回一個指針或者一個指針兼容的類型)

The Target-Action Design Pattern


.......

========================

方法的存儲位置:

>每個類的方法列表都存儲在類對象中

>每個方法都有一個與之對應的SEL類型的對象

>根據一個SEL對象就可以找到方法的地址,進而調用方法

>SEL類型的定義:typedef struct objc selector *SEL;

//SEL 其實是對方法的一種包裝,將方法包裝成一個SEL類型的數據,去找對應的方法地址,找到方法地址就可以調用方法

傳說中的消息是發一個SEL類型的數據,根據其找對應的地址調用方法

以後可以用一些高級特性,直接拿到方法地址,運行,不需要SEL包裝


Person.h文件中:
#import <Foundation/Foundation.h>
@interface Person : NSObject
+ (void)test;
- (void)test;
- (void)test3:(NSString *)abc;
@end

Person.m文件中:
#import "Person.h"
@implementation Person
+ (void)test{
	NSLog(@"-------test-------");
}
- (void)test2{
	//_cmd==@selector(test2);
	NSString *str =NSStringFromSelector( _cmd)//============每個方法都有
	NSLog(@"-------test2------%@",str);
}
- (void)test3:(NSString *)abc{
	NSLog(@"-------tes3------%@",abc);
}
@end

main.m文件中:
#import <Foundation/Foundation.h>
#import "Person.h"
int main(){//測試幾種調用test的方式
	Person *p = [[Person alloc] init];
	[p test2];   //使用_cmd後打印出當前方法,即:test2
	/*
	1.把test2包裝成SEL類型的數據
	2.根據SEL數據找到對應的方法地址
	3.根據方法地址調用對應的方法
	*/
	//利用selector間接調用test2方法
	[p performSelector:@selector(test2)];   //和  [p test2]相同
	[p test3:@"123"];

	//使用SEL:
	NSString *name = @"test2";
	SEL s2 = NSSelectorFromString(name);//把一個字符串轉成SEL類型數據
	NSString *str = NSStringFromSelector(@selector(test));//把SEL對象轉爲NSString對象

	[p performSelector:s2];
	SEL s = @selector(test3:);
	[p performSelector:s withObject:@"456"];
	[p performSelector: @selector(test3:)  withObject:@"123"];//(test:)纔是方法名,不能寫成test

	
	return 0;
}


------- android培訓java培訓、期待與您交流!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章