iOS performSelector(參考)

在項目中淘衙,常常用到performSelector之類的方法鹦筹,而且有很多類似方法;今天就來召集一下消玄!
第一點 performSelector的使用

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
 
    /*performSelector
     - (id)performSelector:(SEL)aSelector;
     - (id)performSelector:(SEL)aSelector withObject:(id)object;
     - (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
     
      - (BOOL)respondsToSelector:(SEL)aSelector;
     */
    
    //其次薯演,進行調(diào)用
    //沒有參數(shù)
    BOOL isNoParam= [self respondsToSelector:@selector(methodNoParam)];
    if (isNoParam) {
        [self performSelector:@selector(methodNoParam)];
    }
    
    //一個參數(shù)
    BOOL isOneParam= [self respondsToSelector:@selector(methodWithOneParam:)];
    if (isOneParam) {
        [self performSelector:@selector(methodWithOneParam:) withObject:@"first"];
    }
    
    //二個參數(shù)
    BOOL isParams= [self respondsToSelector:@selector(methodWithParams: andParamSecond:)];
    if (isParams) {
        [self performSelector:@selector(methodWithParams: andParamSecond:) withObject:@"first" withObject:@"second"];
    }

    //建立動態(tài)的函數(shù)撞芍,然后調(diào)用它們
    NSArray *objectArray = @[@{@"methodName":@"DynamicParameterString:", @"value":@"String"},
                           @{@"methodName":@"DynamicParameterNumber:", @"value":@2}];
    for (NSDictionary *dic in objectArray) {
        SEL selector = NSSelectorFromString([dic objectForKey:@"methodName"]);
        if ([self respondsToSelector:selector]) {
            //這里會有警告:PerformSelector may cause a leak because its selector is unknown
            [self performSelector:selector withObject:[dic objectForKey:@"value"]];
        }
    }
    
    //PerformSelector may cause a leak because its selector is unknown 解決方法
    //1.使用函數(shù)指針方式
    for (NSDictionary *dic in objectArray) {
        SEL selector = NSSelectorFromString([dic objectForKey:@"methodName"]);
        if ([self respondsToSelector:selector]){
            IMP imp = [self methodForSelector:selector];
            void (*func)(id, SEL) = (void *)imp;
            func(self, selector);
        }
    }
    //其它方法消除警告:http://www.tuicool.com/articles/iu6zuu

}

//首先,定義要調(diào)用的方法
- (void)methodNoParam{
    NSLog(@"methodNoParam");
}

- (void)methodWithOneParam:(id)paramFirst{
    NSLog(@"methodWithOneParam: %@", paramFirst);
}

- (void)methodWithParams:(id)paramFirst andParamSecond:(id) paramSecond{
    NSLog(@"methodWithOneParam: %@,%@", paramFirst,paramSecond);
}


- (void)DynamicParameterString:(NSString *)string{
    NSLog(@"DynamicParameterString: %@",string);
}

- (void)DynamicParameterNumber:(NSNumber *)number{
    NSLog(@"DynamicParameterNumber: %@",number);
}

這里需要補充的知識:關(guān)于performSelector調(diào)用和直接調(diào)用方法的區(qū)別
1跨扮、performSelector是運行時系統(tǒng)負責(zé)去找方法的序无,在編譯時候不做任何校驗;如果直接調(diào)用編譯是會自動校驗衡创。
如果methodNoParam愉镰、methodWithOneParam:、methodWithParams: andParamSecond:不存在
那么直接調(diào)用:在編譯時候就能夠發(fā)現(xiàn)(借助Xcode可以寫完就發(fā)現(xiàn))钧汹,但是使用performSelector的話一定是在運行時候才能發(fā)現(xiàn)(此時程序崩潰)丈探;
Cocoa支持在運行時向某個類添加方法,即方法編譯時不存在拔莱,但是運行時候存在碗降,這時候必然需要使用performSelector去調(diào)用。
所以有時候如果使用了performSelector塘秦,為了程序的健壯性讼渊,會使用檢查方法respondsToSelector。
2尊剔、直接調(diào)用方法時候爪幻,一定要在頭文件中聲明該方法的使用,也要將頭文件import進來须误。而使用performSelector時候挨稿, 可以不用import頭文件包含方法的對象,直接用performSelector調(diào)用即可京痢。

3奶甘、performSelector是在iOS中的一種方法調(diào)用方式。他可以向一個對象傳遞任何消息祭椰,而不需要在編譯的時候聲明這些方法臭家。所以這也是runtime的一種應(yīng)用方式。
所以performSelector和直接調(diào)用方法的區(qū)別就在與runtime方淤。直接調(diào)用編譯是會自動校驗钉赁。如果方法不存在,那么直接調(diào)用 在編譯時候就能夠發(fā)現(xiàn)携茂,編譯器會直接報錯你踩。
但是使用performSelector的話一定是在運行時候才能發(fā)現(xiàn),如果此方法不存在就會崩潰。所以如果使用performSelector的話他就會有個最佳伴侶respondsToSelector:;來在運行時判斷對象是否響應(yīng)此方法姓蜂。
備注:runtime?医吊?钱慢?
在這小作總結(jié):OC是運行時語言,只有在程序運行時卿堂,才會去確定對象的類型束莫,并調(diào)用類與對象相應(yīng)的方法。利用runtime機制讓我們可以在程序運行時動態(tài)修改類草描、對象中的所有屬性览绿、方法,就算是私有方法以及私有屬性都是可以動態(tài)修改的穗慕。

// 動態(tài)添加方法
// 開發(fā)場景:如果一個類方法非常多,加載了到內(nèi)存的時候也比較耗費資源,需給每個方法生成映射表,可以使用動態(tài)給某個類,添加方法解決.
// 經(jīng)典面試題:有沒有使用preformSelector,其實主要想問有沒有添加過方法;

performSelector相關(guān)的應(yīng)用:傳遞三個及以上的參數(shù)
第一種:NSInvocation
第二種:把多個參數(shù)封裝成一個參數(shù)
在這里不做描述:詳情參考 https://my.oschina.net/ososchina/blog/644117
第三種:objc_msgSend

NSString *str = @"字符串objc_msgSend";
NSNumber *num = @20;
NSArray *arr = @[@"數(shù)組值1", @"數(shù)組值2"];
SEL sel = NSSelectorFromString(@"ObjcMsgSendWithString:withNum:withArray:");

((void (*) (id, SEL, NSString *, NSNumber *, NSArray *)) objc_msgSend) (self, sel, str, num, arr);

- (void)ObjcMsgSendWithString:(NSString *)string withNum:(NSNumber *)number withArray:(NSArray *)array {
    NSLog(@"%@, %@, %@", string, number, array[0]);
}

參數(shù)中有結(jié)構(gòu)體的處理方式

typedef struct ParameterStruct{
    int a;
    int b;
}MyStruct;

NSString *str = @"字符串 把結(jié)構(gòu)體轉(zhuǎn)換為對象";
NSNumber *num = @20;
NSArray *arr = @[@"數(shù)組值1", @"數(shù)組值2"];

MyStruct mystruct = {10,20};
NSValue *value = [NSValue valueWithBytes:&mystruct objCType:@encode(MyStruct)];

SEL sel = NSSelectorFromString(@"NSInvocationWithString:withNum:withArray:withValue:");
NSArray *objs = [NSArray arrayWithObjects:str, num, arr, value,nil];

[self performSelector:sel withObjects:objs];

- (void)NSInvocationWithString:(NSString *)string withNum:(NSNumber *)number withArray:(NSArray *)array withValue:(NSValue *)value{

    MyStruct struceBack;
    [value getValue:&struceBack];

    NSLog(@"%@, %@, %@, %d", string, number, array[0],struceBack.a);
}

第二點

/**
 在主線程上執(zhí)行指定的方法饿敲,使用默認的模式(NSDefaultRunLoopMode)
 默認的模式指:主線程中的方法進行排隊,是一個循環(huán)隊列逛绵,并且循環(huán)執(zhí)行怀各。
這個函數(shù)表示在主線程上執(zhí)行方法,YES表示需要阻塞主線程术浪,直到主線程將我們的代碼塊執(zhí)行完畢瓢对。

 @param aSelector 要在主線程執(zhí)行的方法,該方法不能有返回值胰苏,并且只能有一個參數(shù)硕蛹。
 @param arg 要傳遞的參數(shù),如果無參數(shù)硕并,就設(shè)為nil法焰。
 @param wait 要執(zhí)行的aSelector方法,是否馬上執(zhí)行倔毙。
 如果設(shè)置為YES:等待當前線程執(zhí)行完以后壶栋,主線程才會執(zhí)行aSelector方法;
 設(shè)置為NO:不等待當前線程執(zhí)行完普监,就在主線程上執(zhí)行aSelector方法贵试。
 如果,當前線程就是主線程凯正,那么aSelector方法會馬上執(zhí)行毙玻。
 
 該方法用途:因為iPhone編程,對UI的修改廊散,只能在主線程上執(zhí)行桑滩。可以用該方法來完成UI的修改允睹。
 */
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait {
       NSLog(@"用的多");
}

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array {

}

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait {
    
}

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array {

}

/**
 在當前線程中執(zhí)行指定的方法运准,使用默認模式幌氮,并指定延遲。

 @param aSelector 指定的方法胁澳。含義同上该互,不在贅述。
 @param anArgument 同上
 @param delay 指定延遲時間(秒)韭畸。
 */
- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay {
      NSLog(@"用的多");
}

- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes {

}

這里需要補充的知識:
Runloop 相當于 win32 里面的消息循環(huán)機制宇智,它可以讓你根據(jù)事件/消息(鼠標消息,鍵盤消息胰丁,觸摸事件随橘,計時器消息等)來調(diào)度線程。
比如:在觸摸 UIView 時之所以能夠激發(fā) touchesBegan/touchesMoved 等等函數(shù)被調(diào)用锦庸。系統(tǒng)會自動為應(yīng)用程序的主線程生成一個與之對應(yīng)的 run loop 來處理其消息循環(huán)机蔗。讓調(diào)用更加簡單。也避免了繁瑣甘萧,復(fù)雜的操作蜒车。
一句話:Runloop是一種消息處理機制!

參考鏈接:
http://www.reibang.com/p/672c0d4f435a
http://blog.sina.com.cn/s/blog_7b9d64af0101bjw4.html
http://blog.csdn.net/meegomeego/article/details/20041887

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末幔嗦,一起剝皮案震驚了整個濱河市酿愧,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌邀泉,老刑警劉巖嬉挡,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異汇恤,居然都是意外死亡庞钢,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進店門因谎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來基括,“玉大人,你說我怎么就攤上這事财岔》缑螅” “怎么了?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵匠璧,是天一觀的道長桐款。 經(jīng)常有香客問我,道長夷恍,這世上最難降的妖魔是什么魔眨? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上遏暴,老公的妹妹穿的比我還像新娘侄刽。我一直安慰自己,他們只是感情好朋凉,可當我...
    茶點故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布州丹。 她就那樣靜靜地躺著,像睡著了一般侥啤。 火紅的嫁衣襯著肌膚如雪当叭。 梳的紋絲不亂的頭發(fā)上茬故,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天盖灸,我揣著相機與錄音,去河邊找鬼磺芭。 笑死赁炎,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的钾腺。 我是一名探鬼主播徙垫,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼放棒!你這毒婦竟也來了姻报?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤间螟,失蹤者是張志新(化名)和其女友劉穎吴旋,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體厢破,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡荣瑟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了摩泪。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笆焰。...
    茶點故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖见坑,靈堂內(nèi)的尸體忽然破棺而出嚷掠,到底是詐尸還是另有隱情,我是刑警寧澤荞驴,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布叠国,位于F島的核電站,受9級特大地震影響戴尸,放射性物質(zhì)發(fā)生泄漏粟焊。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望项棠。 院中可真熱鬧悲雳,春花似錦、人聲如沸香追。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽透典。三九已至晴楔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間峭咒,已是汗流浹背税弃。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留凑队,地道東北人则果。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像漩氨,于是被迫代替她去往敵國和親西壮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,442評論 2 359

推薦閱讀更多精彩內(nèi)容

  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,160評論 30 470
  • 目錄 Objective-C Runtime到底是什么 Objective-C的元素認知 Runtime詳解 應(yīng)用...
    Ryan___閱讀 1,939評論 1 3
  • 平均3個通宵讀完來形容這本書的叫惊,其實不然款青,而我花了三個半天和晚上看完的,故事的每個章節(jié)穿插著好幾個國家霍狰,因為這次長...
    嚴素閱讀 552評論 0 0
  • 當人生還剩下一百個小時抡草,你就會死亡,你會做什么蚓耽? 很多人面對死亡渠牲,更多的是對未知的恐懼,所有活在世界上的人都不知道...
    銀花浩天閱讀 227評論 0 0
  • 今天是2017年2月26日,我讀完了計劃中的第一本書鼎兽,由王臣寫的《今生就這樣開始 三毛傳》答姥,我的讀書感受如下: 讀...
    小米粥毛毛閱讀 971評論 0 1