详解Objective-c Block应用

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束後就被清掉了。要得。

相关推荐