《Objective-C編程 第二版》筆記16:Block對象

Block對象的示例:

^{
    NSLog(@"This is an instruction within a block.");
}

和C函數類似,但是沒有函數名,相應的位置只有一個^符號。^表示這段代碼是一個Block對象。

和函數一樣,Block對象也可以有實參和返回值。

^(double dividend, double divisor){
    double quotient = dividend / divisor;
    return quotient;
}

代碼中兩個double類型的實參,還返回一個double類型的值。

Block對象可以被當作一個實參來傳遞給可以接收block的方法。

 

    創建一個新項目,名稱爲VowelMovement。該項目將使用Block對象枚舉數組中的字符串並移除所有的元音字母,並將去除元音字母的字符串保存到一個新的數組中。

    main.m,創建3個數組對象,一個用於保存最初的字符串,一個用於保存去除了元音字母的字符串,最後一個用於保存需要從字符串中移除的字符。

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //創建兩個數組對象,分別用於保存最初的字符串對象和去除元音字母后的版本
        NSArray *originalStrings = @[@"Sauerkraut",@"Raygun",@"Big Nerd Ranch",@"Mississippi"];
        
        NSLog(@"origianl strings:%@",originalStrings);
        NSMutableArray *devowelizedStrings = [NSMutableArray array];
        //創建數組對象,保存需要從字符串中移除的字符
        NSArray *vowels = @[@"a",@"e",@"i",@"o",@"u"];
        
    return 0;
}

1、使用Block對象

編寫一個Block對象,用於複製一個給定的字符串,並移除給定字符串的所有元音字母,然後將去除元音字母的字符串保存到devowelizedStrings數組中。

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //
        NSArray *originalStrings = @[@"Sauerkraut",@"Raygun",@"Big Nerd Ranch",@"Mississippi"];
        
        NSLog(@"origianl strings:%@",originalStrings);
        NSMutableArray *devowelizedStrings = [NSMutableArray array];
        
        NSArray *vowels = @[@"a",@"e",@"i",@"o",@"u"];
        //聲明Block變量,void是返回類型,第一個()中^表明是一個Block對象,devowelizer是Block對象名稱,後邊的是實參類型
        void (^devowelizer)(id, NSUInteger, BOOL *);
        //將Block對象賦值給變量
        devowelizer = ^(id string, NSUInteger i, BOOL *stop){
            //
            NSMutableString *newString = [NSMutableString stringWithString:string];
            
            //枚舉數組中的字符串,將所有出現的元音字母替換成空字符串
            for(NSString *s in vowels){
                NSRange fullRange = NSMakeRange(0, [newString length]);
                [newString replaceOccurrencesOfString:s withString:@"" options:NSCaseInsensitiveSearch range:fullRange];
            }
            [devowelizedStrings addObject:newString];
        };//Block變量賦值結束
        
    }
    return 0;
}

傳遞Block對象

在main.m中,調用enumerateObjectsUsingBlocks:並傳入devowelizer,然後輸出去除了元音字母的字符串

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        //
        NSArray *originalStrings = @[@"Sauerkraut",@"Raygun",@"Big Nerd Ranch",@"Mississippi"];
        
        NSLog(@"origianl strings:%@",originalStrings);
        NSMutableArray *devowelizedStrings = [NSMutableArray array];
        
        NSArray *vowels = @[@"a",@"e",@"i",@"o",@"u"];
        //
        void (^devowelizer)(id, NSUInteger, BOOL *);
        //
        devowelizer = ^(id string, NSUInteger i, BOOL *stop){
            
            NSMutableString *newString = [NSMutableString stringWithString:string];
            
            //
            for(NSString *s in vowels){
                NSRange fullRange = NSMakeRange(0, [newString length]);
                [newString replaceOccurrencesOfString:s withString:@"" options:NSCaseInsensitiveSearch range:fullRange];
            }
            [devowelizedStrings addObject:newString];
        };//
        //枚舉數組對象,針對每個數組中的對象,執行Block對象devowelizer
        [originalStrings enumerateObjectsUsingBlock:devowelizer];
        NSLog(@"new strings:%@",devowelizedStrings );
        
    }
    return 0;
}

typedef

       Block對象的語法可能會比較複雜。typedef可以將某個Block對象類型定義爲一個新的類型。需要注意的是,不能在方法的實現代碼中使用typedef,應該在實現文件的頂部,或者頭文件內使用typedef

//將Block對象類型定義爲一個新類型
typedef void (^ArrayEnumerationBlock) (id, NSUInteger, BOOL *);


//聲明Block變量
//void (^devowelizer) (id, NSUInteger,BOOL *);
ArrayEnumerationBlock devowelizer;

2、Block對象 VS 其他回調

     上一章介紹過兩種回調機制:委託機制和通告機制。這兩種方法可以很好的完成任務,但是回調的設置代碼回調方法的具體實現無法寫在同一段代碼中。這兩段代碼經常會間隔很遠,甚至會出現在不同的文件中。

     然而,通過Block對象,將回調相關的代碼寫在同一代碼段中。這樣閱讀程序比較方便。

3、深入學習Block對象

返回值

^(double dividend, double divisor){
    double quotient = dividend / divisor;
    return quotient;
}

//在這個示例中,有兩個double類型的實參,返回一個double類型的值。要在變量中保存這個Block,需要聲明一個double類型的變量,然後再將Block賦值給這個變量:
//聲明divBlock變量,這應該是一個Block對象
double (^divBlock)(double,double);

//將Block對象賦給變量
divBlock = ^(double dividend, double divisor){
    double quotient = dividend / divisor;
    return quotient;
}

//調用,像調用函數一樣調用divBlock
double myQuotient = divBlock(42.0, 12.5);

在Block對象中使用self

    爲了避免Block對象捕獲self引起的強引用循環,可以先在Block對象外聲明一個weak指針,然後將這個指針指向Block對象使用的self,最後在Block對象中使用這個新的指針。

__weak BNREmployee *weakSelf = self;//一個弱引用指針

myBlock = ^{
    NSLog(@"Employee:%@",weakSelf);
}

       現在這個Block對象對BNREMployee實例是弱引用,強引用循環打破了。然而由於是弱引用,所以self指向的對象在Block對象執行的時候可能被釋放。爲了避免這種情況,可以在Block對象中創建一個對self的局部強引用。

__weak BNREmployee *weakSelf = self;//一個弱引用指針

myBlock = ^{
    //局部強引用
    BNREmployee *innerSelf = weakSelf;
    NSLog(@"Employee:%@",weakSelf);
}

修改外部變量

    在Block對象中,被捕獲的變量是常數,程序無法修改變量保存的值。

    如果需要在Block對象中修改某個外部變量,則可以在聲明相應的外部變量時,在前面加上__block關鍵字。

__block int counter = 0;

void (^counterBlock)() = ^{counter++ ;};
counterBlock();//counter增加1,數值爲1
counterBlock();//counter增加1,數值爲2

 

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