iOS Block

這篇文章是為了講解ReactiveCocoa做的一個(gè)鋪墊,由于ReactiveCocoa中大量使用Block,所以這里將對(duì)Block進(jìn)行一個(gè)鞏固,當(dāng)然,Block用的很熟悉的朋友,大可不必看這篇文章。

在iOS4.0之后,Block面世,它是一種特殊的數(shù)據(jù)類型。它的本身是一段代碼,特殊在于,它將這段代碼當(dāng)做了變量,然后通過(guò)類似block()這種方式回調(diào)。

寫一個(gè)Block總共分幾步?

答:三步!

  • 聲明
    NSString *(^blockName)(NSString *str1, NSString *str2);
    從前到后依次為返回值類型、block名字、參數(shù)1、參數(shù)2;
  • 定義
 (NSString *)^(NSString *str1, NSString *str2) {
        return [NSString stringWithFormat:@"%@+%@",str1, str2];
    };

注意:Block是一個(gè)語(yǔ)法塊,后面我們要帶“;”的!

  • 調(diào)用
    blockName(@"str1",@"str2");

根據(jù)傳入?yún)?shù)和返回值類型,我們可以認(rèn)為Block有四種類型:

  • 有參有返回值
//聲明&定義
    NSString *(^block5)(NSString *) = ^(NSString *str){
        return [NSString stringWithFormat:@"%@+參數(shù)2", str];
    };
//調(diào)用
    NSLog(@"%@", block5(@"參數(shù)1"));
  • 有參無(wú)返回值
//聲明&定義
    void (^block2)(NSString *) = ^(NSString *str){
        NSLog(@"%@", str);
    };
//調(diào)用
    block2(@"參數(shù)");
  • 無(wú)參有返回值
//聲明&定義
    NSString *(^block4)(void) = ^(void){
        return @"返回值";
    };
//調(diào)用
    NSLog(@"%@", block4());
  • 無(wú)參無(wú)返回值
//聲明&定義
    void (^block1)(void) = ^(void){
        NSLog(@"無(wú)參數(shù) 無(wú)返回值!");
    };
//調(diào)用
    block1();

Block的使用

在Block誕生之前,開(kāi)發(fā)者們用的都是delegate來(lái)完成回調(diào)。在Block面世之后,絕大部分的回調(diào)處理被改為了Block。之所以做出這一改變,跟Block的使用簡(jiǎn)單,靈活等原因是分不開(kāi)的!

這里我以再次封裝AFNetworking為例,來(lái)對(duì)Block回調(diào)進(jìn)行講解。
先分析一下網(wǎng)絡(luò)請(qǐng)求的幾個(gè)必要要素:

  • 域名
  • 請(qǐng)求參數(shù)
  • 網(wǎng)絡(luò)請(qǐng)求成功回調(diào)
  • 網(wǎng)絡(luò)請(qǐng)求失敗回調(diào)
  • 網(wǎng)絡(luò)異?;卣{(diào)

這里面前兩者沒(méi)什么可分析的,主要說(shuō)一下后三個(gè)Block的機(jī)制。
三者我們著重來(lái)講解一個(gè)(網(wǎng)絡(luò)請(qǐng)求成功回調(diào)),因?yàn)槿咧皇菂?shù)和返回的數(shù)據(jù)類型不一樣,大同小異,只要理解了,沒(méi)必要多做解釋。

  • 通過(guò)typedef來(lái)給block起一個(gè)類型名稱
typedef void (^ReturnValueBlock) (id returnValue);//成功回調(diào)
typedef void (^ErrorCodeBlock) (id errorCode);//失敗回調(diào)
typedef void (^FailureBlock)();//錯(cuò)誤回調(diào)

當(dāng)我們要回調(diào)的時(shí)候,我們可以根據(jù)我們的參數(shù)類型、個(gè)數(shù),和返回值類型來(lái)選擇我們用哪種Block。
在網(wǎng)絡(luò)請(qǐng)求的類中聲明這個(gè)方法:

#pragma --mark POST請(qǐng)求方式
-(void) NetRequestPOSTWithRequestURL: (NSString *) requestURLString
                        WithParameter: (NSDictionary *) parameter
                 WithReturnValeuBlock: (ReturnValueBlock) block
                   WithErrorCodeBlock: (ErrorCodeBlock) errorBlock
                     WithFailureBlock: (FailureBlock) failureBlock;

方法中,我們傳入的參數(shù)有三個(gè)Block,他們?nèi)齻€(gè)分別是用之前用typedef聲明的,分別處理網(wǎng)絡(luò)請(qǐng)求的時(shí)候不同的處理。接下來(lái)看看它是怎么實(shí)現(xiàn)的

#pragma --mark POST請(qǐng)求方式
-(void) NetRequestPOSTWithRequestURL: (NSString *) requestURLString
                        WithParameter: (NSDictionary *) parameter
                 WithReturnValeuBlock: (ReturnValueBlock) block
                   WithErrorCodeBlock: (ErrorCodeBlock) errorBlock
                     WithFailureBlock: (FailureBlock) failureBlock
{
    AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
    [manager POST:[NSString stringWithFormat:@"%@%@", BaseUrl, requestURLString] parameters:parameter progress:^(NSProgress * _Nonnull uploadProgress) {
        
    } success:^(NSURLSessionDataTask * _Nonnull task, id  _Nullable responseObject) {
        NSLog(@"requestUrl: %@\nparameter: %@", requestURLString, parameter);
        if ([[responseObject objectForKey:@"status"] integerValue]== 200) {
            block(responseObject);
        } else if ([[responseObject objectForKey:@"status"] integerValue]== 400) {
            errorBlock(responseObject);
        }
    } failureObjc:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error, id responseObject) {
        NSLog(@"%@", responseObject);
        failureBlock();
    }];
}

主要看Success里面,這里面回調(diào)了兩個(gè)block:”block“、”errorBlock“。不知道大家能不能看這兩個(gè)block是在什么時(shí)候回調(diào)的。感覺(jué)應(yīng)該可以看得懂,根據(jù)網(wǎng)絡(luò)請(qǐng)求返回的狀態(tài),”200“表示網(wǎng)絡(luò)請(qǐng)求成功,”400“表示網(wǎng)絡(luò)請(qǐng)求失敗,各家公司的接口應(yīng)該都差不多吧。接下來(lái)就是使用了

由于這段代碼是從公司工程中拿出來(lái)的,所以接口和數(shù)據(jù)的處理都被我刪掉重新簡(jiǎn)化的寫了下
-(void)getTeacherCommentLis{
    NSDictionary *dic = @{@"access_token":[USER_DEFAULT objectForKey:@"access_token"],
                          @"pageNo":[NSNumber numberWithInteger:1]};
    [[ZTAPIClient alloc] NetRequestPOSTWithRequestURL:@"getTeacherCommentLis" WithParameter:dic WithReturnValeuBlock:^(id returnValue) {
               網(wǎng)絡(luò)請(qǐng)求成功,得到返回結(jié)果;
               可以刷新TableView,存儲(chǔ),更新等一系列操作
    } WithErrorCodeBlock:^(id errorCode) {
              網(wǎng)絡(luò)請(qǐng)求失敗,往往是填寫的參數(shù)有問(wèn)題
    } WithFailureBlock:^{
    }];
}

現(xiàn)在來(lái)想一想,回顧一下,以上的操作我們都是在做什么。我們是在哪里聲明的block、又是在哪里定義的、最后又是在哪里調(diào)用的?

  • 在網(wǎng)絡(luò)請(qǐng)求類的聲明文件中,我們用typedef聲明了block;
  • 在網(wǎng)絡(luò)請(qǐng)求的方法中,我們把聲明的block當(dāng)做了參數(shù),傳入到了方法中
  • 在調(diào)用方法的時(shí)候,我們定義了這個(gè)block需要做的操作
  • 在網(wǎng)絡(luò)請(qǐng)求類實(shí)現(xiàn)方法中,我們調(diào)用了block

Block相關(guān)的幾個(gè)關(guān)鍵字

copy

block在使用的過(guò)程中跟對(duì)象一樣會(huì)引起引用計(jì)數(shù)變化。同樣聲明block時(shí),它的內(nèi)存是分配在棧上,隨時(shí)可能被回收,所以,我們需要將他拷貝到堆上。通過(guò)copy可以把block拷貝到堆上,來(lái)保證block不會(huì)被隨時(shí)回收。
@property (nonatomic, copy)void(^block)(NSString *);

__block

在一個(gè)block里面,我們對(duì)block之外的變量是只讀操作,也就是我們只能讀取它的值,不可以更改。像這樣,Xcode會(huì)給你報(bào)一個(gè)這樣的錯(cuò)誤。


block內(nèi)訪問(wèn)外部變量.png

說(shuō)到__block, 它是用于,我們想在block內(nèi)來(lái)改變某個(gè)外部的變量的時(shí)候,我們需要在聲明這個(gè)變量的時(shí)候用“__block”來(lái)修飾。


__block修飾外部變量
__weak

有時(shí)在使用block 的時(shí)候,由于self 是被強(qiáng)引用的,在 ARC 下,當(dāng)編譯器自動(dòng)將代碼中的block從??截惖蕉褧r(shí),block 會(huì)強(qiáng)引用和持有self,而 self 也強(qiáng)引用和持有了 block,這就造成了循環(huán)引用,導(dǎo)致兩者都不能釋放,內(nèi)存泄露。__weak解決循環(huán)引用的理念就是,將其中一者弱化,編程弱引用,也就是引用計(jì)數(shù)不會(huì)增加。 __weak修飾符修飾變量 self,讓 block 不強(qiáng)引用 self,從而破除循環(huán)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容