iOS開發(fā)block

一、基本概念:

Block是一種C語言的數(shù)據(jù)類型,指向結(jié)構(gòu)體的指針,平常我們將Block當(dāng)作一個代碼段使用,相當(dāng)于函數(shù),Block相比于函數(shù)的優(yōu)點是 Block可以當(dāng)做一個參數(shù)傳遞而函數(shù)/方法不能.。我們可以用Block寫一些函數(shù)語句,可以使用多線程。Block也可以作為一個回調(diào),不僅包含回調(diào)期間的代碼,也包含了執(zhí)行期間需要的數(shù)據(jù)。類似于"閉包",閉包的定義是可以從函數(shù)外部訪問函數(shù)內(nèi)部的變量。

二、基本用法:

1)無參無返回值(最簡單形式)

定義格式:void (^block名)() = ^{代碼塊;};

使用格式:block名();

2)無參有返回值(以返回值為int為例)

定義格式:int (^block名)() = ^{代碼塊;};

使用格式:int result = block名();

3)有參無返回值(以參數(shù)為int為例)

定義格式:void (^block名)(int) = ^(int a){代碼塊;};

使用格式:? block名(6);

4)有參有返回值(以參數(shù)、返回值為int為例;可以有多個參數(shù))

定義格式:int (^block名)(int) = ^(int a){代碼塊;};

使用格式:int result = block名(6);

5)利用typedef定義block類型(和指向函數(shù)的指針很像)

定義格式:typedef 返回值類型(^新別名)(參數(shù)類型列表);

例:typedef int (^myBlock)(int,int);

三、Block訪問外部變量

1)在block內(nèi)部可以訪問block外部的變量,但是,這是一個新的內(nèi)存空間變量;

block內(nèi)部也可以定義和block外部同名的變量,此時這個局部變量會屏蔽外部變量的作用域。

2)如果想要在block內(nèi)部修改外部的局部變量,需要給該變量加上__block關(guān)鍵字;原因是加__block,block會引用常量變量的地址,則可以任意修改該變量指向的內(nèi)容。如果不加__block直接在block內(nèi)部修改變量,會編譯報錯,block內(nèi)部變量是只讀的。

四、Block使用技巧和注意事項

1)block的快速提示,輸入inlineBlock 會有代碼提示;

2)block變量用作方法的參數(shù)時,最好把參數(shù)類型列表部分加上具體的參數(shù)名

3)利用block遍歷取值

例: [dict enumerateKeysAndObjectsUsingBlock:^(id? _Nonnull key, id? _Nonnull obj, BOOL * _Nonnull stop) {

}];

5)? block修飾:block的發(fā)展也經(jīng)過了MRC和ARC兩個階段;

MRC情況下:用copy修飾后,如果要在block內(nèi)部使用對象,則需要進(jìn)行__block typeof(Target) blockTarget = Target處理,在block里面用blockTarget 操作。

ARC情況下:如果用copy修飾,該block就會存儲在堆空間以避免在使用時發(fā)生釋放。但會對block的內(nèi)部對象進(jìn)行強(qiáng)引用,導(dǎo)致循環(huán)引用,內(nèi)存無法釋放。 所以block使用 self ,要使用 self 弱引用寫法. 即__weak typeof(self) weakSelf = self;如果用weak修飾block,該block就會存放在??臻g,雖不會出現(xiàn)循環(huán)引用,但容易造成需要使用對象時,對象已經(jīng)不存在的問題,原因是存儲在棧空間的各種數(shù)據(jù)是系統(tǒng)自動處理的,并不需要程序猿手動處理,所以我們也不知道對象什么時候會被釋放。

6)循環(huán)引用

分析循環(huán)(VC代表viewController控制器)

已知 : op --> self(VC) 強(qiáng)引用

如果 self 強(qiáng)引用的對象,對 op 也有強(qiáng)用.那么就會有循環(huán)引用

self(VC) --> queue/OPCache --> op --> self(VC)

所以block使用 self ,要使用 self 弱引用寫法. 即__weak typeof(self) weakSelf = self;

GCD中的block(任務(wù))出現(xiàn)self,會造成循環(huán)引用嗎?? ----- GCD中的block可以直接使用 self

block循環(huán)引用的條件: block------->強(qiáng)應(yīng)用(self)? self ------->強(qiáng)引用(block屬性)

NSOperation 中的blcok中是否可以出現(xiàn) self ?

一般情況下 NSOperationQueue 需要作為一個屬性. 將操作添加到操作隊列中!

注意: 1.確實會出現(xiàn)循環(huán)引用!

但是: 操作一旦執(zhí)行完畢之后,就會被自動銷毀! 所以 NSOperation 中可以出現(xiàn) self.

7)block可以在兩個對象之間進(jìn)行傳值,類似于代理和通知;

以POST請求為例,假如我在A對象中封裝了POST請求的方法,該方法請求回來的數(shù)據(jù)想傳遞給B對象,就可以利用block實現(xiàn):

代碼示例:

"A對象中聲明方法

//MARK:- 一句話封裝POST請求

- (void)POSTRequestWithURLString:(NSString *)urlString andDict:(NSDictionary *)pramarts andSuccessBlock:(successBlock)successblock andFalseBlock:(falseBlock)falseblock ;

"實現(xiàn)方法

- (void)POSTRequestWithURLString:(NSString *)urlString andDict:(NSDictionary *)pramarts andSuccessBlock:(successBlock)successblock andFalseBlock:(falseBlock)falseblock {

//MARK:- 創(chuàng)建請求

NSURL *url = [NSURL URLWithString:urlString];

#warning - POST請求要創(chuàng)建可變請求

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:0 timeoutInterval:15];

//MARK:- 設(shè)置請求體、請求方法等參數(shù)

request.HTTPMethod = @"POST";

NSMutableString *strM = [NSMutableString string];

[pramarts enumerateKeysAndObjectsUsingBlock:^(id? _Nonnull key, id? _Nonnull obj, BOOL * _Nonnull stop) {

NSString *pramKey = key;

NSString *pramValue = obj;

[strM appendFormat:@"%@=%@&",pramKey,pramValue];

}];

NSString *pramart = [strM substringToIndex:strM.length-1];

request.HTTPBody = [pramart dataUsingEncoding:NSUTF8StringEncoding];

//MARK:- 發(fā)送請求

[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

if (data&&!error) {

if (successblock!=nil) {//一定要先判斷block是否為空

successblock( obj,response);//回調(diào)

}

}else{

if (falseblock!=nil) {//同上

falseblock(error);

}

}

}]resume];

}

"B對象調(diào)用方法

[[YQPOSTRequest sharedPOSTRequest] POSTRequestWithURLString:urlStr andDict:pram andSuccessBlock:^(NSData *data, NSURLResponse *response) {

NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);

} andFalseBlock:^(NSError *error) {

NSLog(@"%@",error);

}];

五、解決OC中block循環(huán)引用的三種方式

1)解決循環(huán)引用的第一種方式

//iOS 5.0 引用來解決循環(huán)引用的方式? 和weak屬性關(guān)鍵字作用類似

//當(dāng)對象被系統(tǒng)回收時? 對象的地址 會自動指向 nil? 不會出現(xiàn)野指針訪問

__weak typeof(self) weakSelf = self;

2)解決循環(huán)引用的第二種方式

//? ? __weak typeof(self) weakSelf = self;

//會引起 EXC_BAD_ACCESS 錯誤 是MRC 時代最常見的錯誤? 野指針? --> 壞地址訪問

// 和 assgin屬性關(guān)鍵字的作用類似? 對象被系統(tǒng)回收時 對象的地址不會自動指向nil

// iOS4.0 和block 一起推出的 用來解決循環(huán)引用的

__unsafe_unretained typeof(self) weakSelf = self;

3) 解決循環(huán)引用的第三種方式

//weak-strong-dance wwdc 推出的解決方式? 在AFN中被大量的運(yùn)用到

__weak typeof(self) weakSelf = self;

[self.tools loadData:^(NSString *result) {

//閉包中對弱引用的weakSelf 在強(qiáng)引用一下

__strong typeof(weakSelf) strongSelf = weakSelf;

NSLog(@"%@ %@",result,strongSelf);

}];

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

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

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