NSInvocation如何調(diào)用block

NSInvocation如何調(diào)用block

同步發(fā)布到博客地址NSInvocation如何調(diào)用block

NSInvocation是調(diào)用函數(shù)的另一種方式杂瘸,它將調(diào)用者队腐,函數(shù)名,參數(shù)封裝到一個(gè)對象氓皱,然后通過一個(gè)invoke函數(shù)來執(zhí)行被調(diào)用的函數(shù)河胎,其思想就是命令者模式,將請求封裝成對象幔嗦。
NSMethodSignature 用于描述 method 的類型信息:返回值類型酿愧,及每個(gè)參數(shù)的類型。?

NSInvocation 簡單實(shí)用

NSMethodSignature *signature = [NSInvocationTestViewController instanceMethodSignatureForSelector:@selector(testInstanceMethodArgument1:)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
invocation.target = self;
invocation.selector = @selector(testInstanceMethodArgument1:);
NSString *argument1 = @"string";
[invocation setArgument:&argument1 atIndex:2];
[invocation invoke];

獲取方法簽名的方法

  • instanceMethodSignatureForSelector
  • methodSignatureForSelector
  • signatureWithObjCTypes

[xxx methodSignatureForSelector:@select];

xxxisa 指向的地方的方法列表里面找方法邀泉;

[xxx instanceMethodSignatureForSelector:@select];

直接在 xxx 的 方法列表里面找方法嬉挡。

signatureWithObjCTypes

根據(jù)字符創(chuàng)建簽名叛氨。

具體規(guī)則可以查看蘋果的官方文檔:Type Encodings

[invocation setArgument:&argument1 atIndex:2];

這里設(shè)置參數(shù)要從 2 開始,是因?yàn)槟J(rèn)方法有兩個(gè)參數(shù) 0: self 棘伴,1: SEL 寞埠。

還有一個(gè)點(diǎn)要注意,經(jīng)常當(dāng)我們通過 getReturnValue 獲取返回值的時(shí)候焊夸,容易出現(xiàn)崩潰仁连。

譬如 返回值是 NSString *

 NSString *returnValue;
 NSLog(@"1 returnValue == %@",returnValue);
 [invocation getReturnValue:&returnValue];
 NSLog(@"2 returnValue == %@",returnValue);
 NSLog(@"returnValue %p",returnValue);
 
 ---
 *** -[CFString release]: message sent to deallocated instance 0x60000025db30

這是因?yàn)?getReturnValue 接收的參數(shù)為 void * 類型,在 ARC 模式下阱穗,強(qiáng)轉(zhuǎn)類型導(dǎo)致了內(nèi)存管理的混亂饭冬。下面這張寫法就不會有問題。

void *returnValue = NULL;
NSLog(@"1 returnValue == %@",returnValue);
[invocation getReturnValue:&returnValue];
NSLog(@"2 returnValue == %@",returnValue);
NSString *t = (__bridge NSString *)(returnValue);
NSLog(@"t %p",t);

NSInvocation 如何調(diào)用 block

如何獲取一個(gè) block 的方法簽名

這一段來自于 用 Block 實(shí)現(xiàn)委托方法

通過種種渠道我們可以得知 block揪阶,最終的結(jié)果是一個(gè)結(jié)構(gòu)體昌抠。形式如下

// Block internals.
typedef NS_OPTIONS(int, TBVBlockFlags) {
    TBVBlockFlagsHasCopyDisposeHelpers = (1 << 25),
    TBVBlockFlagsHasSignature          = (1 << 30)
};
typedef struct tbv_block {
    __unused Class isa;
    TBVBlockFlags flags;
    __unused int reserved;
    void (__unused *invoke)(struct tbv_block *block, ...);
    struct {
        unsigned long int reserved;
        unsigned long int size;
        // requires TBVBlockFlagsHasCopyDisposeHelpers
        void (*copy)(void *dst, const void *src);
        void (*dispose)(const void *);
        // requires TBVBlockFlagsHasSignature
        const char *signature;
        const char *layout;
    } *descriptor;
    // imported variables
} *TBVBlockRef;

方法的簽名就位于 TBVBlockRef -> descriptor -> signature 這個(gè)位置。
獲取的方法:

static NSMethodSignature *tbv_signatureForBlock(id block) {
    TBVBlockRef layout = (__bridge TBVBlockRef)(block);
    
    // 沒有簽名鲁僚,直接返回空
    if (!(layout->flags & TBVBlockFlagsHasSignature)) {
        return nil;
    }
    
    // 獲取 descriptor 指針
    void *desc = layout->descriptor;
    
    // 跳過 reserved 和 size 成員
    desc += 2 * sizeof(unsigned long int);
    
    // 如果有 Helpers 函數(shù)炊苫, 跳過 copy 和 dispose 成員
    if (layout->flags & TBVBlockFlagsHasCopyDisposeHelpers) {
        desc += 2 * sizeof(void *);
    }
    
    // desc 為 signature 指針的地址,轉(zhuǎn)換下給 objcTypes
    char *objcTypes = (*(char **)desc);
    
    return [NSMethodSignature signatureWithObjCTypes:objcTypes];
}

對比了發(fā)現(xiàn)和 Aspects 里面獲取 block 簽名的方法一致冰沙。

如何為 block 設(shè)置參數(shù)

block 的簽名不像 select侨艾, 第一個(gè)參數(shù)是返回類型,第二個(gè)參數(shù)才是真正的參數(shù)拓挥,并不像 select 第二個(gè)參數(shù)是 : 代表 SEL.

   for (int idx = 1; idx < methodSignature.numberOfArguments; idx++) {
        
        // 獲取參數(shù)類型
        const char *type = [methodSignature getArgumentTypeAtIndex:idx];
        NSLog(@"----%s",type);
        if ([[NSString stringWithUTF8String:type] isEqualToString:@"\@\"NSString\""] ) {
            NSString *argument1 = @"----123---";
            [blockInvocation setArgument:&argument1 atIndex:idx];
        }else if ([[NSString stringWithUTF8String:type] isEqualToString:@"#"] )
        {
            Class cls = [NSSet class];
            [blockInvocation setArgument:&cls atIndex:idx];
        }
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唠梨,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子侥啤,更是在濱河造成了極大的恐慌当叭,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,013評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盖灸,死亡現(xiàn)場離奇詭異蚁鳖,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)糠雨,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,205評論 2 382
  • 文/潘曉璐 我一進(jìn)店門才睹,熙熙樓的掌柜王于貴愁眉苦臉地迎上來徘跪,“玉大人甘邀,你說我怎么就攤上這事】迓” “怎么了松邪?”我有些...
    開封第一講書人閱讀 152,370評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哨查。 經(jīng)常有香客問我逗抑,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,168評論 1 278
  • 正文 為了忘掉前任邮府,我火速辦了婚禮荧关,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘褂傀。我一直安慰自己忍啤,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,153評論 5 371
  • 文/花漫 我一把揭開白布仙辟。 她就那樣靜靜地躺著同波,像睡著了一般。 火紅的嫁衣襯著肌膚如雪叠国。 梳的紋絲不亂的頭發(fā)上未檩,一...
    開封第一講書人閱讀 48,954評論 1 283
  • 那天,我揣著相機(jī)與錄音粟焊,去河邊找鬼冤狡。 笑死,一個(gè)胖子當(dāng)著我的面吹牛项棠,可吹牛的內(nèi)容都是我干的筒溃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,271評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼沾乘,長吁一口氣:“原來是場噩夢啊……” “哼怜奖!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起翅阵,我...
    開封第一講書人閱讀 36,916評論 0 259
  • 序言:老撾萬榮一對情侶失蹤歪玲,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后掷匠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體滥崩,經(jīng)...
    沈念sama閱讀 43,382評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,877評論 2 323
  • 正文 我和宋清朗相戀三年讹语,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了钙皮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 37,989評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡顽决,死狀恐怖短条,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情才菠,我是刑警寧澤茸时,帶...
    沈念sama閱讀 33,624評論 4 322
  • 正文 年R本政府宣布,位于F島的核電站赋访,受9級特大地震影響可都,放射性物質(zhì)發(fā)生泄漏缓待。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,209評論 3 307
  • 文/蒙蒙 一渠牲、第九天 我趴在偏房一處隱蔽的房頂上張望旋炒。 院中可真熱鬧,春花似錦签杈、人聲如沸国葬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,199評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汇四。三九已至,卻和暖如春踢涌,著一層夾襖步出監(jiān)牢的瞬間通孽,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,418評論 1 260
  • 我被黑心中介騙來泰國打工睁壁, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留背苦,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,401評論 2 352
  • 正文 我出身青樓潘明,卻偏偏與公主長得像行剂,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子钳降,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,700評論 2 345

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