iOS_block問題

前言:

最近遇到了一個block的循環(huán)引用的問題,才發(fā)現(xiàn)我對block還一知半解,為此,對自己的理解做了一下正整理。

目錄:

1、什么是block ?有什么作用?
2、block為什么使用copy修飾?
3、block為什么會造成循環(huán)引用?怎么解決?
4、block中基本數(shù)據(jù)類型,數(shù)值無法更改。

1、什么是block?有什么作用?

代碼塊Block是蘋果在iOS4開始引入的對C語言的擴展,用來實現(xiàn)匿名函數(shù)的特性,Block是一種特殊的數(shù)據(jù)類型,其可以正常定義變量、作為參數(shù)、作為返回值,特殊地,Block還可以保存一段代碼,在需要的時候調(diào)用,目前Block已經(jīng)廣泛應用于iOS開發(fā)中,常用于GCD、動畫、排序及各類回調(diào)。存儲的數(shù)據(jù)是一個函數(shù)體。使用Block,就可以像其他標準函數(shù)一樣,傳入?yún)?shù),并得到返回值。

block的格式:
     a:Block的返回值類型,可以為空(void);
     b:Block對象名稱,可以理解為變量名;
     ^:塊的語法標記,聲明b為一個Block對象; 
     c:第一個參數(shù)類型
     d:第二個參數(shù)類型
     name1,name2:參數(shù)名;
     {}:Block代碼塊的主題部分。
block的聲明:
例子:控制器A,控制器B,在A中點擊button push到B,pop時從B傳值到A。block為B中的屬性和方法。
方式一:
typedef void(^testBlock)(void); // 定義類型,取別名
@property (nonatomic, copy) testBlock Block; // 再聲明屬性

實現(xiàn):
B中:
_testBlock(@"1");

A中:
b.testBlock = ^(NSString *text) {
      nslog(@"%@",text);
 };

方式二:
@property (nonatomic, copy) void(^test1Block)(NSString *text); // 直接聲明屬性

實現(xiàn):
B中:
_test1Block(@"1");

A中:
b.test1Block = ^(NSString *text) {
      nslog(@"%@",text);
 };

方式三:
-(void)testWithBlock:(void(^)(NSString *text))block; // 作為函數(shù)參數(shù)

實現(xiàn):
B中:
- (void)testWithBlock:(void (^)(NSString *))block{
    block(@"1");
}

A中:
[a testWithBlock:^(NSString *text) {
        nslog(@"%@",text);
 }];
2、block為什么使用copy修飾?

a、block在創(chuàng)建的時候默認分配的內(nèi)存是在棧上,而不是在堆上。這樣的話其本身的作用域是屬于創(chuàng)建時候的作用域,一旦在創(chuàng)建的作用域之外調(diào)用就會導致程序的崩潰。所以使用了copy將其拷貝到堆內(nèi)存上。
b、block創(chuàng)建在棧上,而block的代碼中可能會用到本地的一些變量,只有將其拷貝到堆上,才能用這些變量

3、block為什么會造成循環(huán)引用?怎么解決?

self 與 block 相互持有,形成保留環(huán),無法釋放,導致循環(huán)引用內(nèi)存泄露

例子一:
self.b.test1Block = ^(NSString *text) {
      nslog(@"%@",text);
       [self.test1_btn setTitle:text forState:UIControlStateNormal];
 };

情況:未執(zhí)行dealloc 內(nèi)存泄露  self->b->block->self 
解決辦法:打破retain cycle
__weak typeof(self) weakSelf = self;
[weakSelf.test1_btn setTitle:text forState:UIControlStateNormal];
例子二:
LHQTest2ViewController *b = [[LHQTest2ViewController alloc]init];
    [self.navigationController pushViewController:b animated:YES];
    b.test2Block = ^(NSString *text) {
        [self.test1_btn setTitle:text forState:UIControlStateNormal];
    };

情況:執(zhí)行dealloc 不泄露 b->block->self
例子三:
    b = [[LHQTest2ViewController alloc]init]; //test2為局部變量
    [self.navigationController pushViewController:test2 animated:YES];
    b.test2Block = ^(NSString *text) {
        [self.test2_btn setTitle:text forState:UIControlStateNormal];
    };
情況:未執(zhí)行dealloc 內(nèi)存泄露 self->b->block->self 
解決辦法:與例子一一樣
例子四:
    self.b.test2Block = ^(NSString *text) {
        _msg = text; // _msg未局部變量
    };
情況:未執(zhí)行dealloc 內(nèi)存泄露 self->b->block->self 
解決辦法:打破retain cycle
__weak typeof(self) weakSelf = self;
    self.b.test2Block = ^(NSString *text) {
        __strong typeof(weakSelf) strongSelf = weakSelf;
      // strongSelf和原來的self并沒有直接關系,因為strongSelf是通過weakSelf得來的,而weakSelf又沒有強引用原來的sel
        strongSelf->_msg = text;
    };
4、block中基本數(shù)據(jù)類型,數(shù)值無法更改。

對于基本數(shù)據(jù)類型,進入到block中會被當做常量處理

//如果需要在block中對num進行修改,需要加上關鍵字__block
 //(我們也可以用static關鍵字進行修飾)
__block int  num = 10; // 使進入到block塊中的變量不被當做常量來使用
b.test2Block = ^(NSString *text) {
     num += 1;
    NSLog(@"num is %d",num);
 };

ending 有什么錯誤的地方請指正。

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

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

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