ZuoYanDeHuangHun 2011-07-29
详解Objective-c block应用是本文要介绍的内容,主要介绍的是Objective-c block应用,不多说,先来看详细内容。
Apple在C, Objective-C, C++加上Block@延申用法。目前只有Mac 10.6 和iOS 4有支援。Block是由一堆可绦械某淌浇M成,也可以Q做]有名字的Function (Anonymous function)。如果是Mac 10.6 或 iOS 4.0 之前的平台可以利用 http://code.google.com/p/plblocks/ @project得以支援BlockZ法。
Apple有一叫做GCD(Grand Central Dispach)的新功能,用在同步(concurrency)的h境下有更好的效率。BlockZ法a生的C就是碜造GCD,用Block包好一工作量交oGCD,GCD有一宏^的野可以矸峙CPU,GPU,Memory的硐伦詈玫Q定。
Block 介
Block其行楹Function很像,最大的差e是在可以存取同一Scope的抵怠
Block wL成@
^(魅盗) {行橹黧w};
Blockw_^是"^",接著是由小括所包起淼盗(比如 int a, int b, float c),行榈闹黧w由大括包起恚S忻~叫做block literal。行橹黧w可以用return回髦担ecompiler自愚kR出怼H绻]有盗幸@(void)。
看列子
^(int a) {return a*a;};
@是代表Block鬏入值的平方值(int a 就是盗校return a*a; 就是行橹黧w)。得主we最後要加";"因槭⑹觯{}最後也要要加";"因Block是物件w。
用法就是
int result = ^(int a) {return a*a;} (5);
很怪吧。後面小括e的5 划成a的入值然後由Block出5*5 = 25指定oresult@怠
有]有我稽c的方法不然每次都要@NL?有。接下硪榻B一叫Block Pointer的|西砗化我的法。
Block Pointer是@有娴
回髦 (^名字) (盗);
直接砜匆列子
int (^square) (int); // 有一叫square的Block Pointer,其所指向的Block是有一int 入和 int 出 square = ^(int a ) {return a*a ;}; // Block w指定o square
使用Block Pointer的例子
int result = square(5); // 感X上不就是funtion的用法幔恳部梢园Block Pointer成鹘o一function,比如f
void myFuction( int (^mySquare) (int) ); // function 的宣告
魅胍有一int入和int出的Block 型e的
呼叫@myFunction的r候就是@雍艚
int (^mySqaure) (int) = ^(int a) {return a*a;}; // 先o好一有w的block pointer叫mySquare myFunction( mySqaure ) ; //把mySquare@block pointeromyFunction@function
或是不用block pointer 直接o一block w,就@
myFunction( ^(int a) {return a*a} ) ;
成Objective-C method 的魅胫档脑都是要把型e在登懊嫒会峒由闲±ㄌ,因些就要@
-(void) objcMethod:( int (^) (int) ) square; // square 档男e是 int (^) (int)
x文至此是不是Block有基本的JR? 接下砦要Block相P的行楹吞厣
首先是砜匆幌略Blocke面存取外部档姆椒
存取
1. 可以x取和Block pointer同一scope的抵担
{ int outA = 8; int (^myPtr) (int) = ^(int a) {return outA+a;}; // block e面可以x同一scope的outA的值 int result = myPtr(3); // result is 11 }
我再砜匆很有趣的例子
{ int outA = 8; int (^myPtr) (int) = ^(int a) {return outA+a;}; // block e面可以x同一scope的outA的值 outA = 5; // 在呼叫myPtr之前改outA的值 int result = myPtr(3); // result 的值是 11K不是 8 }
事上呢,myPtr在其主w用到outA@抵档r候是做了一copy的幼靼outA的值copy下怼K灾outA即使Q了新的值myPtrecopy的值是]有影到的。
要注意的是,@指的值是档闹担绻@档闹凳且w的位置,Q句f,@凳pointer的,它指到的值是可以在blocke被改的。
{ NSMutableArray * mutableArray = [NSMutableArray arrayWithObjects:@"one",@"two",@"three",nil]; int result = ^(int a) { [mutableArray removeLastObject]; return a*a;} (5); NSLog(@"test array %@", mutableArray); }
原本mutableArray的值是{@"one",@"two",@"three"}在blocke被更改mutableArray所指向的物件後,mutableArray的值就怀{@"one",@"two"}
2. 直接存取static 的
{ static int outA = 8; int (^myPtr) (int) = ^(int a) {return outA+a;}; // block e面可以x同一scope的outA的值 outA = 5; // 在呼叫myPtr之前改outA的值 int result = myPtr(3); // result 的值是 8,因outA是static 苯臃渲 }
甚至可以在blocke面直接改outA的值比如@
{ static int outA = 8; int (^myPtr) (int) = ^(int a) { outA= 5; return outA+a;}; // block e面改outA的值 int result = myPtr(3); // result 的值是 8,因outA是static 苯臃渲 }
3. Block Variable
在某登懊嫒绻由闲揎字__block 的(注意block前有下底),@涤址Qblock variable。那N在blocke就可以任意修改此抵担抵档母淖也可以知道。
{ __block int num = 5; int (^myPtr) (int) = ^(int a) { return num++;}; int (^myPtr2) (int) = ^(int a) { return num++;}; int result = myPtr(0); result = myPtr2(0); }
因myPtr和myPtr2都有用到num@block variable,最後result的值就7
生命周期和w管理
因block也是^承自NSObject,所以其生命周期和w的管理也就非常之重要。
block一_始都是被放到stacke,Q句f其生命周期S著method或functionY束就换厥眨鸵话阕档纳芷谝印
P於w的管理遵循@要c
1. block pointer的wmethod或functionY束後就磺宓
2. 如果要保存block pointer的w要用-copy指令,@block pointer就环诺heape
(1)block 主we用到的block variable 也话岬heap 而有新的w位置,且一K更新有用到@block variable 的block都指到新的位置
(2)一般的variable值copy
(3)如果主we用到的variable是object的,此objectretain, block releaser也release
(4)block variable e用到的object是不retain的
首先砜匆幌逻@例子
typedef int (^MyBlock)(int); MyBlock genBlock(); int main(){ MyBlock outBlock = genBlock(); int result = outBlock(5); NSLog(@"result is %d",[outBlock retainCount] ); // segmentation fault NSLog(@"result is %d",result ); return 0 ; } MyBlock genBlock() { int a = 3; MyBlock inBlock = ^(int n) { return n*a; }; return inBlock ; }
此程式由genBlockea生的block再指定omain function的outBlock担绦羞@程式玫
Segmentation fault
(]:有r候把 genBlocke的a 去掉就可以跑出Y果的情形,@是系ycache住w,K不是inBlock真得一直存在,久了是换厥眨f不要以槭Φ法)
表示我用到了不用的w,在@例子的情r下是在genBlocke的inBlock翟return的r候就被回收了,outBlocko法有一合法的w位置-retainCount就]意x了。
如果@r候需要保留inBlock的值就要用-copy指令,genBlock改成
MyBlock genBlock() { int a = 3; MyBlock inBlock = ^(int n) { return n*a; }; return [inBlock copy] ; }
@[inBlock copy]的回髦稻环诺heap,就可以一直使用(得要release)
绦薪Y果是
result is 1 result is 15
再次提醒要得release outBlock。
如果一回[inBlock copy]的值就不再需要的r候可以@
MyBlock genBlock() { int a = 3; MyBlock inBlock = ^(int n) { return n*a; }; return [[inBlock copy] autorelease] ; }
-copy指令是榱艘block stack搬到heap,autorelease是榱似叫nretainCount加到autorelease oop ,回髦岬鹊绞录Y束就清掉。
接下硎block存取到的local variable是物件的型e,然後做copy 指令r
MyBlock genBlock() { int a = 3; NSMutableString * myString = [NSMutableString string]; MyBlock inBlock = ^(int n) { NSLog(@"retain count of string %d",[myString retainCount]); return n*a; }; return [inBlock copy] ; }
Y果〕
retain count of string 2
@Y果和上面2.3提到的一樱local variable被retain了
那再碓2.4,在local variable前面加上__block
MyBlock genBlock() { int a = 3; __block NSMutableString * myString = [NSMutableString string]; MyBlock inBlock = ^(int n) { NSLog(@"retain count of string %d",[myString retainCount]); return n*a; }; return [inBlock copy] ; }
绦械慕Y果就是
retain count of string 1
Block Copying注意事
如果在Class methode面做copying block幼鞯脑
1. 在Blocke如果有直接存取到self,tselfretain
2. 在Blocke如果取存到instance variable (o直接或是accessor),tselfretain
3. 取存到local variable所碛械objectr,@objectretain
我砜匆自的Class
@interface MyObject : NSObject { NSString * title; void (^myLog) (NSString * deco); } -(void) logName; @end @implementation MyObject -(id) initWithTitle:(NSString * ) newTitle{ if(self = [super init]){ title = newTitle; myLog = [^(NSString * deco) { NSLog(@"%@%@%@",deco, title, deco );} copy]; } return self; } -(void) logName{ myLog(@"=="); } -(void ) dealloc{ [myLog release]; [title release]; [super dealloc]; } @end
在main e使用如下
MyObject * mObj = [[MyObject alloc] initWithTitle:@"Car"]; NSLog(@"retainCount of MyObject is %d",[mObj retainCount] ); [mObj logName];
其绦械慕Y果
retainCount of MyObject is 2 ==Car==
因樵MyObject的建子emyLog@block pointer用了title@instance variable然後就retain self也就是MyObject的物件。
M量不要@,斐retain cycle,改善的方法是把建子改成@
-(id) initWithTitle:(NSString * ) newTitle{ if(self = [super init]){ title = newTitle; myLog = [^(NSString * deco) { NSLog(@"%@%@%@",deco, newTitle, deco );} copy]; } return self; }
在Block主we用newTitle@刀皇title。@self就不retain了。
最後一小陷井
void (^myLog) (void); BOOL result ; if(result) myLog = ^ {NSLog(@"YES");}; else myLog = ^ {NSLog(@"NO");}; myLog();
@雍芸赡芫掉了,因myLog w在if 或是elseY束後就被清掉了。要得。