load/initalize/MethodSwizzling/Block

前言

2016年6月7號(hào)開(kāi)始load/initalize/KVO/KVC/Block冤荆,并通過(guò)代碼實(shí)現(xiàn)

load/initalize

  • NSObject是大多數(shù)Objective-C類層次結(jié)構(gòu)的根類仙粱,通過(guò)繼承NSObject對(duì)象寒瓦,擁有Objective-C運(yùn)行時(shí)對(duì)象能力基本的接口
  • load/initalize 兩個(gè)方法,由每個(gè)類Objective - C運(yùn)行時(shí)自動(dòng)調(diào)用

load 簡(jiǎn)介

當(dāng)一個(gè)類或分類被添加到Objective-C運(yùn)行時(shí)既绩;會(huì)調(diào)用load方法锥惋,實(shí)現(xiàn)這個(gè)方法來(lái)加載執(zhí)行特定類的行為畏梆。

Discussion:

  • load方法消息會(huì)被發(fā)送到動(dòng)態(tài)加載和靜態(tài)鏈接的類和類別,只有當(dāng)被加載新的類或類別實(shí)現(xiàn)該方法才可以響應(yīng)坏挠。

初始化時(shí)執(zhí)行順序如下:

  • 對(duì)所有鏈接框架初始化 (#import)
  • 加載所有l(wèi)oad方法
  • 初始化所有C++ 靜態(tài)變量和靜態(tài)方法和使用attribute(constructor) 關(guān)鍵字聲明的函數(shù)
  • 初始化所有鏈接到你的框架 (在Link Binary With Libraries導(dǎo)入的框架)

注意

  • 該類的load方法調(diào)用在所有父類的load方法之后
  • 該分類的load方法調(diào)用在對(duì)應(yīng)類的load方法之后

使用場(chǎng)景

在自定義實(shí)現(xiàn)load方法時(shí)芍躏,可以很安全地(線程安全)提前獲取其他毫無(wú)相關(guān)類消息,并且在消息還沒(méi)實(shí)現(xiàn)時(shí)降狠,手動(dòng)去實(shí)現(xiàn)該消息(也就是說(shuō)load方法常常應(yīng)用于Swizzling Method
操作)

initalize 簡(jiǎn)介

在初始化類之前收到第一個(gè)消息,也就是說(shuō)对竣,對(duì)該類進(jìn)行初始化時(shí)被調(diào)用

Discussion

  • 在程序中向類或者與其繼承的任何子類發(fā)送第一條消息前,runtime會(huì)以線程安全的方式來(lái)向類發(fā)起initialize消息榜配。
  • 父類會(huì)在子類之前收到這條消息否纬。如果子類沒(méi)有實(shí)現(xiàn)initialize方法,由于Runtime機(jī)制
    將按順序調(diào)用實(shí)現(xiàn)該類繼承而來(lái)的父類initialize方法蛋褥,父類的initialize可能會(huì)被調(diào)用多次,針對(duì)這種情況解決方法代碼:
+ (void)initialize {
  if (self == [ClassName self]) {
    // ... do the initialization ...
  }
}

使用該方法注意點(diǎn):

在一個(gè)線程安全的方式下進(jìn)行初始化時(shí)临燃,在不同的類initialize被調(diào)用的順序是不保證的,環(huán),使用initialize方法時(shí)應(yīng)盡量做少量且必要的工作谬俄。具體而言柏靶,initialize方法內(nèi)部實(shí)現(xiàn)了同步鎖如果在方法內(nèi)實(shí)現(xiàn)復(fù)雜的邏輯,容易會(huì)導(dǎo)致死鎖溃论。因此屎蜓,不應(yīng)該依賴于initialize復(fù)雜的初始化,而應(yīng)該限制它的簡(jiǎn)單钥勋,可以使用init炬转、new等方法實(shí)現(xiàn)初始化。

特別注意

initialize每個(gè)類只會(huì)被調(diào)用一次算灸,如果你想為類或分類實(shí)現(xiàn)自定義初始化方法可以使用load方法進(jìn)行Swizzling Method操作,后面會(huì)簡(jiǎn)單講下FDTemplateLayoutCell框架如何使用Swizzling Method

Method Swizzling 簡(jiǎn)介

  • 使用Method Swizzling可以改變現(xiàn)有的Selector的實(shí)現(xiàn)一項(xiàng)處理技術(shù)扼劈,方法的調(diào)用在Objective - C中運(yùn)行時(shí),通過(guò)改變Selector映射到該類的底層函數(shù)調(diào)度表,來(lái)修改方法的實(shí)現(xiàn).
  • 在Objective-C實(shí)現(xiàn)擴(kuò)展方法可以使用Category來(lái)覆蓋系統(tǒng)方法菲驴,系統(tǒng)會(huì)優(yōu)先調(diào)用Category中的代碼荐吵,然后在調(diào)用原類中的代碼,如果我們?cè)谝延械腃ategory想實(shí)現(xiàn)UITableViewDelegate/UITableViewSource代理方法,往往就會(huì)使用Method Swizzling赊瞬,而且很輕松做到這一點(diǎn)先煎,可以通過(guò)新建UITableView Category,在其分類使用+(load)Method Swizzling替換方法代理巧涧,例如調(diào)用reloadData等方法薯蝎,F(xiàn)DTemplateLayoutCell框架就是這么做的。

Method Swizzling應(yīng)用場(chǎng)景

  • 跟蹤視圖控制器ViewDidLoad谤绳、viewWillAppear 占锯、viewDidAppear實(shí)現(xiàn),如果多個(gè)ViewController重復(fù)使用代碼,可以在UIViewController分類在load方法中替換其實(shí)現(xiàn)方法

  • 實(shí)現(xiàn)UITableViewDelegate缩筛、UITableViewDataSource自定義代理方法消略,例如在編寫(xiě)框架時(shí),用到UITableViewDelegate歪脏、UITableViewDataSource代理疑俭,替換具體實(shí)現(xiàn)名稱

Swizzling應(yīng)該總是在dispatch_once中執(zhí)行

  • 因?yàn)镸ethod Swizzling會(huì)改變?nèi)譅顟B(tài),需要提供一切預(yù)防措施給Runtime婿失。GCD的dispatch_once原子性就是一個(gè)很好的預(yù)防措施钞艇,無(wú)論有多少個(gè)線程,確保代碼塊恰好執(zhí)行一次豪硅。

  • Selectors, Methods, & Implementations
    在Objective - C中,實(shí)現(xiàn) Selectors, Methods, Implementations是指在Runtime的特定方面哩照,實(shí)現(xiàn)消息發(fā)送時(shí)往往會(huì)用到他們

Selectors(typedef struct objc_selector *SEL):用于表示在運(yùn)行時(shí)方法的名稱。
Method(typedef struct objc_method Method
):表示類的方法
Implementation(typedef id (
IMP)(id, SEL, ...)
): 這個(gè)數(shù)據(jù)類型是指向一個(gè)指針函數(shù)實(shí)現(xiàn)方法

Method Swizzling使用

//
//  UIViewController+MethodSwizzlingCategoryExample.m
//  LoadInitalizeKVOKVCBlockExample
//
//  Created by lmj  on 16/6/8.
//  Copyright ? 2016年 linmingjun. All rights reserved.
//

#import "UIViewController+MethodSwizzlingCategoryExample.h"
#import <objc/runtime.h>
@implementation UIViewController (MethodSwizzlingCategoryExample)


+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,^{
        Class class= [self class];
        
        SEL originalSelector = @selector(viewDidLoad);
        SEL swizzledSelector = @selector(swizzledViwDidLoad);
        // 通過(guò)class_getInstanceMethod()函數(shù)從當(dāng)前class對(duì)象中的method list獲取method結(jié)構(gòu)體
        Method originalMethod = class_getInstanceMethod(class, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
        
        // 如果是類方法:
        // Class class = object_getClass((id)self);
        // ...
        // Method originalMethod = class_getClassMethod(class, originalSelector);
        // Method swizzledMethod = class_getClassMethod(class, swizzledSelector);
        
        // 使用class_addMethod()函數(shù)對(duì)Method Swizzling做了一層驗(yàn)證懒浮,如果self沒(méi)有實(shí)現(xiàn)swizzledSelector交換的方法飘弧,會(huì)導(dǎo)致失敗
        BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));
        
        if (didAddMethod) { // 如果self沒(méi)有實(shí)現(xiàn)swizzledViwDidLoad方法识藤,class_replaceMethod向?qū)ο笏鶎俚念悇?dòng)態(tài)添加所需的selector:,如果swizzledSelector沒(méi)有實(shí)現(xiàn)次伶,
            
            
            
            // class_replaceMethod痴昧,它有兩種不同的行為。當(dāng)類中沒(méi)有想替換的原方法時(shí)冠王,該方法會(huì)調(diào)用class_addMethod來(lái)為該類增加一個(gè)新方法赶撰,也因?yàn)槿绱耍琧lass_replaceMethod在調(diào)用時(shí)需要傳入types參數(shù)柱彻,而method_exchangeImplementations和method_setImplementation卻不需要豪娜。
            class_replaceMethod(class,
                                swizzledSelector,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod));
        } else {// 通過(guò)class_addMethod()的驗(yàn)證,如果self實(shí)現(xiàn)了swizzledViwDidLoad這個(gè)方法哟楷,class_addMethod()函數(shù)將會(huì)返回NO瘤载,進(jìn)行交換了。
            method_exchangeImplementations(originalMethod, swizzledMethod);
        }
        
        
    });
    
}

#pragma mark - Method Swizzling

- (void)swizzledViwDidLoad {
    // 在swizzledViwDidLoad方法內(nèi)部調(diào)用[self swizzledViwDidLoad];時(shí)卖擅,執(zhí)行的是UIViewController的viewDidLoad方法鸣奔。
    // 該方法調(diào)用 [self swizzledViwDidLoad]; 不會(huì)造成死循環(huán);因?yàn)閟wizzledViwDidLoad已經(jīng)被指定為viewDidLoad方法磨镶,所以這里實(shí)質(zhì)調(diào)用的是[self viewDidLoad];方法溃蔫,經(jīng)過(guò)調(diào)試如果不使用這行代碼程序運(yùn)行結(jié)果相同,但是 Mattt Thompson指出這行代碼是為了防止?jié)撛诘奈kU(xiǎn)或麻煩琳猫,體現(xiàn)一個(gè)優(yōu)秀程序員的良好素養(yǎng).
    [self swizzledViwDidLoad];
    NSLog(@"swizzledViwDidLoad: %@", self);
}

@end

 SEL originalSelector = @selector(viewDidLoad);
 SEL swizzledSelector = @selector(swizzledViwDidLoad);

 Method originalMethod = class_getInstanceMethod(class, originalSelector)
 Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);

1.通過(guò)class_getInstanceMethod()函數(shù)從當(dāng)前class對(duì)象中的method list獲取method結(jié)構(gòu)體

BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod));

2.使用class_addMethod()函數(shù)對(duì)Method Swizzling做了一層驗(yàn)證,如果ViewController沒(méi)有viewDidLoad(書(shū)寫(xiě)過(guò)程可能寫(xiě)成viewDidLoadd等錯(cuò)誤)私痹,swizzledSelector交換的方法脐嫂,會(huì)導(dǎo)致失敗,返回YES

method_exchangeImplementations(originalMethod, swizzledMethod);

3.通過(guò)class_addMethod()的驗(yàn)證紊遵,如果self實(shí)現(xiàn)了swizzledViwDidLoad這個(gè)方法账千,class_addMethod()函數(shù)將會(huì)返回NO,進(jìn)行交換了暗膜。

swizzledViwDidLoad方法內(nèi)調(diào)用[self swizzledViwDidLoad]原因:

  • 在swizzledViwDidLoad方法內(nèi)部調(diào)用[self swizzledViwDidLoad];時(shí)匀奏,執(zhí)行的是UIViewController的viewDidLoad方法。
  • 該方法調(diào)用 [self swizzledViwDidLoad]時(shí)候不會(huì)造成死循環(huán)学搜;因?yàn)閟wizzledViwDidLoad已經(jīng)被指定為viewDidLoad方法娃善,所以這里實(shí)質(zhì)調(diào)用的是[self viewDidLoad];方法,經(jīng)過(guò)調(diào)試如果不使用這行代碼程序運(yùn)行結(jié)果相同瑞佩,但是 Mattt Thompson指出這行代碼是為了防止?jié)撛诘奈kU(xiǎn)或麻煩聚磺,體現(xiàn)一個(gè)優(yōu)秀程序員的良好素養(yǎng).

FDTemplateLayoutCell使用Method Swizzling

  • FDIndexPathHeightCacheInvalidation(UIViewTableView Category)

+ (void)load {
    // All methods that trigger height cache's invalidation(觸發(fā)高度緩存失效的所有方法)
    SEL selectors[] = {
        @selector(reloadData),
        @selector(insertSections:withRowAnimation:),
        @selector(deleteSections:withRowAnimation:),
        @selector(reloadSections:withRowAnimation:),
        @selector(moveSection:toSection:),
        @selector(insertRowsAtIndexPaths:withRowAnimation:),
        @selector(deleteRowsAtIndexPaths:withRowAnimation:),
        @selector(reloadRowsAtIndexPaths:withRowAnimation:),
        @selector(moveRowAtIndexPath:toIndexPath:)
    };
    // sizeof(selectors) / sizeof(SEL) =  (9(數(shù)組大小))* SEL  / SEL; 一種用C語(yǔ)言計(jì)算個(gè)數(shù)的常用的技巧
    for (NSUInteger index = 0; index < sizeof(selectors) / sizeof(SEL); ++index) {
        SEL originalSelector = selectors[index];
        
        SEL swizzledSelector = NSSelectorFromString([@"fd_" stringByAppendingString:NSStringFromSelector(originalSelector)]);
        Method originalMethod = class_getInstanceMethod(self, originalSelector);
        Method swizzledMethod = class_getInstanceMethod(self, swizzledSelector);
     
        method_exchangeImplementations(originalMethod, swizzledMethod);
    }
}
  • 為什么在項(xiàng)目調(diào)用reloadData調(diào)用自動(dòng)計(jì)算高度以及緩存,原因就在這里炬丸,在Objective-C實(shí)現(xiàn)擴(kuò)展方法可以使用Category來(lái)覆蓋系統(tǒng)方法瘫寝,系統(tǒng)會(huì)優(yōu)先調(diào)用Category中的代碼,然后在調(diào)用原類中的代碼,如果我們?cè)谝延械腃ategory想實(shí)現(xiàn)UITableViewDelegate/UITableViewSource代理方法,往往就會(huì)使用Method Swizzling焕阿,可以通過(guò)新建UITableView Category咪啡,在其分類使用+(load)Method Swizzling替換方法代理(內(nèi)部計(jì)算cell高度,緩存高度)暮屡,再執(zhí)行項(xiàng)目當(dāng)中UITableViewDelegate/UITableViewDataSource代理方法
  • 寫(xiě)到這里撤摸,先寫(xiě)其他內(nèi)容,有空再對(duì)FDTemplateLayoutCell框架所有類的源碼進(jìn)行分析栽惶,并且實(shí)現(xiàn)擴(kuò)展

block

本章介紹了塊和變量之間的相互作用愁溜,包括內(nèi)存管理

block變量的類型

在block作為對(duì)象代碼中,變量可以用五種不同的方式處理外厂,其中有是三種標(biāo)準(zhǔn)類型的變量冕象,如同一個(gè)函數(shù):

  • 全局變量,包括靜態(tài)局部變量
  • 全局函數(shù)(在技術(shù)上不是變量)
  • 在函數(shù)內(nèi)的局部變量

block還支持其他兩種類型的變量

  • 以__block修飾的變量,block代碼塊是可變的汁蝶,任何引用快內(nèi)的代碼內(nèi)存會(huì)從棧區(qū)復(fù)制到堆區(qū)

  • 通過(guò)const來(lái)修飾的變量

以下規(guī)則適用于block中使用變量

  • 全局變量是可訪問(wèn)的渐扮,包括在同一Scope(范圍)里的靜態(tài)變量

  • 傳遞給block參數(shù)都可以訪問(wèn)(就像函數(shù) 的參數(shù))

  • 局部棧區(qū)(非靜態(tài))在同一Scope(范圍)里以const修飾的局部變量(在于block外的變量可以無(wú)縫地直接在block內(nèi)部使用,而且在block內(nèi)變量發(fā)生變化的不會(huì)體現(xiàn)到block外)

  • 局部變量聲明在該block的范圍內(nèi),它的行為完全像一個(gè)函數(shù)的局部變量,每次調(diào)用block時(shí)掖棉,都會(huì)對(duì)變量進(jìn)行一次copy操作(從棧區(qū)Copy到堆區(qū))墓律,這些變量可以作為常量或在block內(nèi)作為引用變量

  • 下面的示例演示了局部非靜態(tài)變量的使用:

- (void)blockExample1 {

    int x = 123;
     
    void (^printXAndY)(int) = ^(int y) {
     
        printf("%d %d\n", x, y);
    };
     
    printXAndY(456); 

}
// prints: 123 456

局部非靜態(tài)變量試圖將一個(gè)的值賦給塊內(nèi)作為一個(gè)新值會(huì)導(dǎo)致一個(gè)錯(cuò)誤:

- (void)blockExample2 {

    int x = 123;
     
    void (^printXAndY)(int) = ^(int y) {
     
        x = x + y; // error
        printf("%d %d\n", x, y);
    };

}
// Error
  • 你可以指定一個(gè)可變的具有讀寫(xiě)功能的輸入變量,通常?應(yīng)用__block存儲(chǔ)類型來(lái)聲明變量幔亥。也可以通過(guò)與__block數(shù)據(jù)類型相似的耻讽、但他們又是排斥的數(shù)據(jù)類型來(lái)聲明,例如寄存器帕棉、自動(dòng)针肥、靜態(tài)局部變量,
    詳見(jiàn)地址:寄存器香伴、自動(dòng)慰枕、靜態(tài)關(guān)鍵字詳細(xì)說(shuō)明

  • 要允許一個(gè)變量在block內(nèi)改變,使用__block存儲(chǔ)類型來(lái)修飾變量即纲,如果在棧區(qū)聲明的block具帮,進(jìn)行任何的拷貝操作造成超出frame的末尾存儲(chǔ)時(shí),將會(huì)造成棧區(qū)的破壞
    下面的例子演示了在一個(gè)給定的詞法范圍內(nèi)的多個(gè)塊可以同時(shí)使用一個(gè)共享變量

  • 作為一次優(yōu)化低斋,block開(kāi)始存儲(chǔ)在棧區(qū)蜂厅,可以使用Block_copy對(duì)block進(jìn)行copy操作(或在Objective-C會(huì)進(jìn)行一次copy操作(ARC機(jī)制)),變量將從棧區(qū)拷貝到堆區(qū)拔稳,因此葛峻,一個(gè)__block聲明的變量地址是由時(shí)間而改變的巴比。在這里有兩__block變量進(jìn)一步的限制:他們不能改變數(shù)組長(zhǎng)度术奖,并且不能包含C99可變長(zhǎng)度的數(shù)組結(jié)構(gòu)礁遵。

下面的例子說(shuō)明了如何使用一個(gè)__block變量:

__block int x = 123; //  x lives in block storage
 
void (^printXAndY)(int) = ^(int y) {
 
    x = x + y;
    printf("%d %d\n", x, y);
};
printXAndY(456); // prints: 579 456
// x is now 579

下面的例子顯示了幾個(gè)類型的變量的相互作用:

對(duì)象和block變量

作為block變量提供Objective-C和C++對(duì)象和其他block的支持

Objective-C 對(duì)象

  • 當(dāng)一個(gè)block被拷貝時(shí),它會(huì)對(duì)block內(nèi)使用的對(duì)象變量創(chuàng)建一個(gè)強(qiáng)引用采记。
  • 如果在一個(gè)方法中實(shí)現(xiàn)并使用一個(gè)block:

1.如果你通過(guò)引用訪問(wèn)的實(shí)例變量佣耐,那么這個(gè)block會(huì)對(duì)self產(chǎn)生強(qiáng)引用。
2.如果你通過(guò)值來(lái)訪問(wèn)實(shí)例變量唧龄,那么這個(gè)block會(huì)對(duì)這個(gè)變量本身產(chǎn)生強(qiáng)引用兼砖。

下面的例子說(shuō)明了這兩種不同的情況

dispatch_async(queue, ^{
    // instanceVariable is used by reference, a strong reference is made to self
    doSomethingWithObject(instanceVariable);
});
 
 
id localVariable = instanceVariable;
dispatch_async(queue, ^{
    /*
      localVariable is used by value, a strong reference is made to localVariable
      (and not to self).
    */
    doSomethingWithObject(localVariable);
});


dispatch_async(queue, ^{
    // instanceVariable is used by reference, a strong reference is made to self
    doSomethingWithObject(instanceVariable);
});
 
 
id localVariable = instanceVariable;
dispatch_async(queue, ^{
    /*
      localVariable is used by value, a strong reference is made to localVariable
      (and not to self).
    */
    doSomethingWithObject(localVariable);
});

dispatch_async(queue, ^{

    // instanceVariable is used by reference, a strong reference is made to self
    doSomethingWithObject(instanceVariable);
});
 
 
id localVariable = instanceVariable;
dispatch_async(queue, ^{
    /*
      localVariable is used by value, a strong reference is made to localVariable
      (and not to self).
    */
    doSomethingWithObject(localVariable);
});

C ++對(duì)象

  • 一般在block內(nèi)可以使用c++對(duì)象。

  • 在一個(gè)成員函數(shù),成員變量和函數(shù)的引用是通過(guò)隱含的this指針既棺,從而出現(xiàn)可變進(jìn)口讽挟。
    指針,從而出現(xiàn)可變。 如果一個(gè)塊被復(fù)制丸冕,則有兩點(diǎn)考慮:

  • 如果你有一個(gè)__block
    存儲(chǔ)類的東西是一個(gè)基于堆棧的c++對(duì)象,那么平常copy
    使用構(gòu)造函數(shù)耽梅。

  • 如果您使用任何其他的c++基于堆棧的對(duì)象在一塊,它必須有一個(gè)const copy
    構(gòu)造函數(shù)。 然后復(fù)制使用c++對(duì)象的構(gòu)造函數(shù)胖烛。

  • 如果你有一個(gè)__block存儲(chǔ)器修飾的類而且是基于堆棧的C++對(duì)象眼姐,則通常使用Copy構(gòu)造函數(shù)。如果你在block內(nèi)使用其他基于堆棧C++對(duì)象佩番,它必須有一個(gè)const拷貝構(gòu)造函數(shù)众旗。然后,對(duì)C ++對(duì)象的構(gòu)造函數(shù)使用一次Copy操作趟畏。

調(diào)用一個(gè)block

如果你聲明一個(gè)block作為一個(gè)變量,可以使用它作為一個(gè)函數(shù),如下兩個(gè)例子的使用

int (^oneFrom)(int) = ^(int anInt) {
    return anInt - 1;
};
 
printf("1 from 10 is %d", oneFrom(10));
// Prints "1 from 10 is 9"
 
float (^distanceTraveled)(float, float, float) =
                         ^(float startingSpeed, float acceleration, float time) {
 
    float distance = (startingSpeed * time) + (0.5 * acceleration * time * time);
    return distance;
};
 
float howFar = distanceTraveled(0.0, 9.8, 1.0);
printf:  howFar:4.9

通常贡歧,你將一個(gè)block作為一個(gè)函數(shù)或一個(gè)方法的參數(shù)傳遞給一個(gè)block。在這些情況下赋秀,通常創(chuàng)建一個(gè)“inline(內(nèi)聯(lián))”塊艘款。

使用block作為函數(shù)參數(shù)

你可以通過(guò)一個(gè)block作為一個(gè)函數(shù)參數(shù),如同其他參數(shù)一樣沃琅。然而,在很多情況下蜘欲,你不需要聲明block益眉;相反,你只需簡(jiǎn)單地實(shí)現(xiàn)它們姥份,然后使用inline(內(nèi)聯(lián))它們作為一個(gè)參數(shù)郭脂。下面的例子使用了qsort_b功能。qsort_b類似于標(biāo)準(zhǔn)的qsort_r功能澈歉,以最后參數(shù)作為一個(gè)block展鸡。

char *myCharacters[3] = { "TomJohn", "George", "Charles Condomine" };
 
qsort_b(myCharacters, 3, sizeof(char *), ^(const void *l, const void *r) {
    char *left = *(char **)l;
    char *right = *(char **)r;
    return strncmp(left, right, 1);
});
// Block implementation ends at "}"
 
// myCharacters is now { "Charles Condomine", "George", "TomJohn" }

下面的例子演示了如何使用block與dispatch_apply功能。 dispatch_apply聲明如下:

void dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));

功能塊用于提交多次調(diào)用調(diào)度隊(duì)列埃难。它需要三個(gè)參數(shù)莹弊,第一個(gè)指定的迭代次數(shù)來(lái)執(zhí)行涤久;二是指定一個(gè)被提交的隊(duì)列,第三個(gè)是block本身忍弛,而這個(gè)block本身又需要一個(gè)單一的參數(shù)作為當(dāng)前的迭代次數(shù)响迂。
可以使用dispatch_apply打印出迭代索引

#include <dispatch/dispatch.h>
size_t count = 10;
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
 
dispatch_apply(count, queue, ^(size_t i) {
    printf("%u\n", i);
});
printf: 0
        2
        1
        3
        4
        5
        6
        7
        8
        9

使用block作為方法參數(shù)

Cocoa提供了一種方法使用block的數(shù)量。 你通過(guò)block作為一個(gè)方法的參數(shù)就像任何其他參數(shù)细疚。

NSArray *array = @[@"A", @"B", @"C", @"A", @"B", @"Z", @"G", @"are", @"Q"];
NSSet *filterSet = [NSSet setWithObjects: @"A", @"Z", @"Q", nil];
 
BOOL (^test)(id obj, NSUInteger idx, BOOL *stop);
 
test = ^(id obj, NSUInteger idx, BOOL *stop) {
 
    if (idx < 5) {
        if ([filterSet containsObject: obj]) {
            return YES;
        }
    }
    return NO;
};
 
NSIndexSet *indexes = [array indexesOfObjectsPassingTest:test];
 
NSLog(@"indexes: %@", indexes);
 
/*
Output:
indexes: <NSIndexSet: 0x10236f0>[number of indexes: 2 (in 2 ranges), indexes: (0 3)]
*/

拷貝block方法

你可以copy和release模塊:
也可以使用C函數(shù)蔗彤,如下兩個(gè)函數(shù)

Block_copy();

Block_release();

為了避免內(nèi)存泄漏,必須始終平衡Block_copy()
與Block_release()兩種操作

避免兩種block書(shū)寫(xiě)

避免block在for/while循環(huán)和判斷語(yǔ)句內(nèi) (that is, ^{ ... }),,表示該block的是局部數(shù)據(jù)結(jié)構(gòu)的地址疯兼,棧的局部數(shù)據(jù)結(jié)構(gòu)的范圍是封閉的復(fù)合語(yǔ)句然遏,所以你應(yīng)該避免在下面的例子中顯示的模式:

面試提問(wèn):

load 與 initialize 的區(qū)別
答:load :
(1)load方法在這個(gè)文件被程序裝載時(shí)調(diào)用 (2)如果一個(gè)類實(shí)現(xiàn)了load
方法,在調(diào)用這個(gè)方法前會(huì)首先調(diào)用父類的load (3)如果一個(gè)類沒(méi)有實(shí)現(xiàn)load
方法吧彪,那么就不會(huì)調(diào)用它父類的load方法(4)添加一個(gè)子類的分類時(shí)待侵,在分類添加load方法時(shí),調(diào)用順序parent->child->category(5)在Compile Sources中来氧,文件的排放順序就是其裝載順序诫给,自然也就是load方法調(diào)用的順序(除了父子類關(guān)系的描述)
(6)load方法是線程安全的,它內(nèi)部使用了鎖啦扬,所以我們應(yīng)該避免線程阻塞在load
方法中中狂。
initialize:(1)實(shí)例化一個(gè)對(duì)象時(shí)調(diào)用,只會(huì)調(diào)用一次(2)在initialize
方法內(nèi)部也會(huì)調(diào)用父類的方法扑毡,即使子類沒(méi)有實(shí)現(xiàn)initialize方法胃榕,也會(huì)調(diào)用父類的方法

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瞄摊,隨后出現(xiàn)的幾起案子勋又,更是在濱河造成了極大的恐慌,老刑警劉巖换帜,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件楔壤,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡惯驼,警方通過(guò)查閱死者的電腦和手機(jī)蹲嚣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)祟牲,“玉大人隙畜,你說(shuō)我怎么就攤上這事∷当矗” “怎么了议惰?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)乡恕。 經(jīng)常有香客問(wèn)我言询,道長(zhǎng)俯萎,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任倍试,我火速辦了婚禮讯屈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘县习。我一直安慰自己涮母,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布躁愿。 她就那樣靜靜地躺著叛本,像睡著了一般。 火紅的嫁衣襯著肌膚如雪彤钟。 梳的紋絲不亂的頭發(fā)上来候,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音逸雹,去河邊找鬼营搅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛梆砸,可吹牛的內(nèi)容都是我干的转质。 我是一名探鬼主播,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼帖世,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼休蟹!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起日矫,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赂弓,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后哪轿,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體盈魁,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年窃诉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了备埃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡褐奴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出于毙,到底是詐尸還是另有隱情敦冬,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布唯沮,位于F島的核電站脖旱,受9級(jí)特大地震影響堪遂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜萌庆,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一溶褪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧践险,春花似錦猿妈、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至占遥,卻和暖如春俯抖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓦胎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工芬萍, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人搔啊。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓柬祠,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親坯癣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子瓶盛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

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

  • 轉(zhuǎn)至元數(shù)據(jù)結(jié)尾創(chuàng)建: 董瀟偉,最新修改于: 十二月 23, 2016 轉(zhuǎn)至元數(shù)據(jù)起始第一章:isa和Class一....
    40c0490e5268閱讀 1,679評(píng)論 0 9
  • 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的轉(zhuǎn)載 這篇文章完全是基于南峰子老師博客的...
    西木閱讀 30,544評(píng)論 33 466
  • 前言 到了今天終于要"出院"了示罗,要總結(jié)一下住院幾天的收獲惩猫,談?wù)凴untime到底能為我們開(kāi)發(fā)帶來(lái)些什么好處。當(dāng)然它...
    一縷殤流化隱半邊冰霜閱讀 23,351評(píng)論 56 317
  • 繼上Runtime梳理(四) 通過(guò)前面的學(xué)習(xí)蚜点,我們了解到Objective-C的動(dòng)態(tài)特性:Objective-C不...
    小名一峰閱讀 741評(píng)論 0 3
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法轧房,類相關(guān)的語(yǔ)法,內(nèi)部類的語(yǔ)法绍绘,繼承相關(guān)的語(yǔ)法奶镶,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,581評(píng)論 18 399