個人理解 OO是個什麼東西?大致都是經過這樣的過程 從高到低,
1. 先把最上層的東西拿來用了,理解了抽象概念之間的關係,也就是說先學會使用
2. 然而掌握內裏要理,可以使得在使用抽象方法的時候 更加得心應手
3. block 就是一個設計好的語法, 本文羅列了在實際代碼編寫中常見的 block ‘症狀’。
註釋:代碼中羅列了個人對一概念,是爲了幫助理解分析這些‘症狀’,沒有直指核心,只爲了從抽象————》細節的一個熟悉過程。
#import "MyObjc.h"
@interface MyObjc ()
@property (nonatomic, strong)void(^PropertyBlockA)(id something);
@end
@implementation MyObjc
void (^GlobalBlockA)(id something);
- (void)blockCaseExcute{
// 一、關於block對象和一般NSObject對象間的 持有關係(引用關係)循環引用問題的症狀
//Case_01(reference) 直接聲明一個全局block,不是對象的屬性成員,塊中直接使用self無問題
GlobalBlockA = ^(id something) {
NSLog(@"something is:%@ | %@",something,self);
};
//Case_02(reference) 使用與當前對象存在持有關係的成員block,塊中直接使用self有警告提示
//Xcode警告提示:Capturing‘self’strongly in this block is likely to lead to a retain cycle
_PropertyBlockA = ^(id something) {
NSLog(@"something is:%@ | %@",something,self);
};
/*
有幾個概念
1.其實block也是一個對象快,存在自己的isa結構。
2. block pointer的實體在method或function結束後就會被清掉
3.蘋果設計,block 同樣遵循引用計數機制,
PropertyBlockA 已經是MyObjc所持有的屬性成員變量,在上面的代碼塊中PropertyBlockA又引用持有自身的MyObjc對象(self),不難理解它們相互持有導致一個retain cycle了吧。
*/
// 二、 關於block 對塊區 變量進行修改的 __block修飾症狀
//Case_03(variable change) 直接使用block塊,對外部的變量值進行修改,編譯器會給出報錯
//Xcode 報錯提示:Variable is not assignable(missing __block type specifier)
NSString *strValue = @"originString";
void(^VarBlockA)() = ^{
// strValue = @"newString";
};
//Case_04(__book variable) 使用block塊,對__block 修飾的變量進行修改,可執行正常
__block NSString *strOrigin = @"oldString";
void (^VarBlockB)() = ^{
strOrigin = @"newString";
};
VarBlockB();
/*
有幾個概念
4.block 塊默認對統一區塊(scope)變量的引用是做了一個const副本的拷貝處理的,也就會說 Case_03這種情況下,塊中strValue和外部聲明strValue已經不是一回事兒了
5.蘋果設計,爲了避免編者Case_03的情況,乾脆禁止塊內對塊外變量進行直接修改,所以直接讓Xcode給出報錯提示。但是爲了解決該問題引入了__block字段
6.__block 聲明的棧變量的引用被複制到了堆裏,複製之後棧上的以及產生的堆上的 block 都會引用這個堆上的變量。也就是說它保證了塊內外引用一致
*/
// 三、關於block 對塊區 變量進行處理時候, 數值變量和指針對象的不同症狀
//Case_05(nomal variable) 輸出打印結果是200 而不是300。
int autoVarA = 100;
void (^VarBlockC)() = ^ {
NSLog(@"%d",autoVarA + 100);
};
autoVarA = 200;
VarBlockC();
//Case_06(pointer variable) 輸出打印結果是56789,而不是0123456789.
NSMutableString *muString = [NSMutableString stringWithString:@"0123456789"];
void (^VarBlockD)() = ^ {
[muString deleteCharactersInRange:NSMakeRange(0, 5)];
NSLog(@"%@",muString);
// muString = [NSMutableString stringWithString:@"098765421"];
};
VarBlockD();
/*
有幾個概念
7.Case_05 的情況這個可以看出,對變量 做const 副本的處理實在塊代碼主體部分實現的,先於塊代碼的實際調用時機。
8.Case_06 (要注意的是 4和7概念強調的是變量值),如果這個變量的值是一個指針的位置,即這個變量是pointer的話,它指到的值是可以在block裏被改變的(遵循__block的是pointer本身).
*/
// 四、 關於block 在遇見static 關鍵字時候的 應對處理症狀
//Case_07(static variable) 輸出打印結果是200 ,而不是100
static int autoValueB = 100;
void (^VarBlockEOne)() = ^{
NSLog(@"%d",autoValueB);
};
autoValueB = 200;
VarBlockEOne();
//Case_08(static variable) 輸出打印結果是300, 並且不需要__block關鍵字就能在塊區對autoValueB進行修改
void (^VarBlockETwo)() = ^{
autoValueB = 300;
NSLog(@"%d",autoValueB);
};
VarBlockETwo();
/*
有幾個概念
9. static 本身的特點,修飾的變量地址是靜態存在,始終不變,任何地方對它的使用都會尋到同一塊存儲區(指針地址)
10.因此Case_07的效果, Case_08可以推導出一個結論:static的優先級是很高的,block也要滿足了它的特徵
*/
//附註 參考文檔
//http://wiki.jikexueyuan.com/project/objc-zen-book/communication-between-objects.html
//http://blog.csdn.net/tlb203/article/details/7653817
}