1:block的循環引用問題最主要記住兩點:
如果【block內部】使用【外部聲明的強引用】訪問【對象A】, 那么【block內部】會自動產生一個【強引用】指向【對象A】
如果【block內部】使用【外部聲明的弱引用】訪問【對象A】, 那么【block內部】會自動產生一個【弱引用】指向【對象A】
2:
#import "ViewController.h" #import "XMGPerson.h" @interface ViewController () @property (nonatomic, copy) int (^sumBlock)(int, int); @property (nonatomic, assign) int a; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; [self test5]; /* 如果【block內部】使用【外部聲明的強引用】訪問【對象A】, 那么【block內部】會自動產生一個【強引用】指向【對象A】 如果【block內部】使用【外部聲明的弱引用】訪問【對象A】, 那么【block內部】會自動產生一個【弱引用】指向【對象A】 */ } /** * 不可行 */ - (void)test6 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ // block1 XMGPerson *strongP = weakP; NSLog(@"block1 -- %@", strongP.name); dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ // block2 NSLog(@"block2 -- %@", weakP.name); }); }; p.block(); } /** * 可行 */ - (void)test5 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ // block1 NSLog(@"beign-------"); XMGPerson *strongP = weakP; dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ // block2 // NSLog(@"block2 -- %@", weakP.name); NSLog(@"block2 -- %@", strongP.name); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // block3 NSLog(@"block3 -- %@", strongP.name); }); }); }; p.block(); } /** * 不可行 */ - (void)test4 { XMGPerson *p = [[XMGPerson alloc] init]; p.name = @"Jack"; p.block = ^{ // block1 NSLog(@"beign-------"); dispatch_time_t when = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)); dispatch_after(when, dispatch_get_main_queue(), ^{ // block2 NSLog(@"after-----------%@", p.name); }); }; p.block(); } /** * 不可行 */ - (void)test3 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ // block1 NSLog(@"beign-------"); XMGPerson *strongP = weakP; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // block2 NSLog(@"after-----------%@", strongP.name); }); }; p.block(); } /** * 可行 */ - (void)test2 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ // block1 NSLog(@"beign-------"); XMGPerson *strongP = weakP; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ // block2 NSLog(@"after-----------%@", strongP.name); }); }; p.block(); } - (void)test1 { XMGPerson *p = [[XMGPerson alloc] init]; __weak XMGPerson *weakP = p; p.name = @"Jack"; p.block = ^{ NSLog(@"-----------%@", weakP.name); }; } #pragma mark - 其他 - (void)test:(int (^)(int, int))sumBlock { } - (void)run:(int)a { } - (void)testBlock { [self test:^(int a, int b){ return a + b; }]; void (^block)() = ^{ NSLog(@"-------"); }; block(); int (^sumBlock)(int, int) = ^(int num1, int num2){ return num1 + num2; }; sumBlock(10, 10); int a = 10; /* 返回值類型 (^block的變量名)(形參類型列表) = ^(形參列表) { // block代碼 }; block的變量名(實參列表); */ } @end
總結:1:block的定義:1:block以屬性定義的時候,用copy修飾,
@property (nonatomic, copy) void (^block)();無參數無返回值,因為block默認是在堆里,需要將堆中的block,copy到棧中才能使用 2:block的非屬性定義:1:無參數無返回值:
其中 void (^block)() 表示聲明一個名稱為block的block,block的類型表示為:void (^)(),右邊的為block任務的代碼塊,
block();表示調用block,右邊為左邊的block賦值
void (^block)() = ^{ NSLog(@"-------"); }; block();
2:有參數有返回值的block:左邊int (^sumBlock)(int, int)定義一個有參數有返回值的block:sumBlock,而右邊的block給左邊的block賦值,寫法:參數寫在^(int a,int b)其中ab為block的參數,返回值寫在block的代碼塊中。
sumBlock(10, 10);調用block,並未block傳遞參數
^(int num1, int num2){
return num1 + num2;
};
int (^sumBlock)(int, int) = ^(int num1, int num2){ return num1 + num2; }; sumBlock(10, 10);
3:block作為參數傳遞:1: block作為參數傳遞 - (void)test:(int (^)(int, int))sumBlock,實現該方法,調用block傳遞參數 2:在外部調用test方法,其中ab就為傳遞的參數,
[self test:^(int a, int b){
NSLog(@"%d",a+b);
return a + b;
}];
- (void)test:(int (^)(int, int))sumBlock
{
sumBlock(2,1);
}
4:1:block的循環引用:XMGPerson alloc init 之后在內存中產生一個對象,name 和 block是該對象的屬性(因為用copy修飾,也就相當於強引用),則該對象會對這兩個屬性分別有一個強引用,創建完對象之后,有一個強指針p指向該對象(指針里存放的是對象的地址,變量創建之后無論是全局變量還是局部變量都會有一個強引用),__weak那部分代碼是將強指針p的地址復制給一個弱指針weakSelf,此時弱指針weakSelf會有一個弱引用指向person對象,p.name = @"JACK";此時name屬性會對jack有一個強引用,block會對賦值的block有一個強引用。此時不會立即調用block代碼塊中的任務,但是此時會檢測block代碼塊中有無引用外部變量(即使是外部無引用,在after中引用了,也算block中引用了外部變量,此時會對訪問的該對象有一個強引用或是弱引用,代碼塊中有引用weakP,所以會產生一個弱引用),再執行代碼調用block,執行block代碼塊中的任務,將一個弱引用weakP指針賦值給一個強引用,此時block代碼塊中的strongP會對person對象有一個強引用,在執行gcd延遲函數,此時會產生延遲函數的block塊,會檢測延遲函數中有無引用外界的變量,有引用了strongP,則會產生一個強引用指向person對象,此時的代碼塊不立即執行(但是系統會有一個強指針指向該代碼塊,如圖2),此時會執行到方法結束,強指針p銷毀,弱指針weakp銷毀,strongP執行完銷毀,但此時block2還指向person對象,所以person對象不會銷毀,能打印出name 2:像類似於GCD的延遲函數在block中,想要保住對象使其不備銷毀,就在block中定義一個強引用指向就可以了


