objective-c block 旧版详解

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得以支援Block�Z法。

Apple有一��叫做GCD(Grand Central Dispach)的新功能,用在同步�理(concurrency)的�h境下有更好的效率。Block�Z法�a生的��C就是�碜造�GCD,用Block包好 一��工作量交�oGCD,GCD有一��宏�^的�野可以�矸峙�CPU,GPU,Memory的�硐伦詈玫�Q定。

Block �介


Block其��行�楹�Function很像,最大的差�e是在可以存取同一��Scope的��抵怠�
Block ���w���L成�@��

^(�魅��盗�) {行�橹黧w};


Block���w�_�^是"^",接著是由小括�所包起�淼��盗�(比如 int a, int b, float c),行�榈闹黧w由大括�包起�恚��S忻��~叫做block literal。行�橹黧w可以用return回�髦担�型�e��被compiler自�愚k�R出�怼H绻��]有��盗幸��@���(void)。
看��列子

^(int a) {return a*a;};

�@是代表Block��回�鬏�入值的平方值(int a 就是��盗校�return a*a; 就是行�橹黧w)。�得主�w�e最後要加";"因�槭�⑹觯�而整��{}最後也要要加";"因��Block是��物件���w。
用法就是

int result = ^(int a) {return a*a;} (5);

很怪吧。後面小括��e的5 ��被��成a的�入值然後�由Block�出5*5 = 25指定�oresult�@����怠�
有�]有��我稽c的方法不然每次都要���@�N�L?有。接下�硪�介�B一��叫Block Pointer的�|西�砗�化我��的��法。


Block Pointer是�@�有�告的

回�髦� (^名字) (��盗�);


直接�砜匆��列子

int (^square) (int);  // 有一��叫squareBlock 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 pointer�omyFunction�@��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有基本的�J�R? 接下�砦��要��Block相�P的行�楹吞厣�
首先是�砜匆幌略�Block�e面存取外部��档姆椒�

存取���

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 的值�是 11�K不是 8
}

 事��上呢,myPtr在其主�w用到outA�@����抵档�r候是做了一��copy的�幼靼�outA的值copy下�怼K�以之後outA即使�Q了新的值��於myPtr�ecopy的值是�]有影�到的。
要注意的是,�@��指的值是��档闹担�如果�@����档闹凳且������w的位置,�Q句��f,�@����凳��pointer的�,它指到的值是可以在block�e被改�的。

{
        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"}在block�e被更改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 ����直接反��其值
}

甚至可以在block�e面直接改�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前有���下底�),�@����涤址Q��block variable。那�N在block�e就可以任意修改此��抵担���抵档母淖�也可以知道。

{
    __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一�_始都是被放到stack�e,�Q句��f其生命周期�S著method或function�Y束就��被回收,和一般��档纳�命周期一�印�
�P於����w的管理�遵循�@���要�c
1. block pointer的���w��在method或function�Y束後就��被清掉
2. 如果要保存block pointer的���w要用-copy指令,�@��block pointer就��被放到heap�e
    2.1 block 主�w�e用到的block variable 也��被搬到heap 而有新的����w位置,且一�K更新有用到�@��block variable 的block都指到新的位置
    2.2 一般的variable值��被copy 
    2.3 如果主�w�e用到的variable是object的�,此object��被retain, block release�r也��被release
    2.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 ;
}

此程式由genBlock�e�a生的block再指定�omain function的outBlock��担��绦羞@��程式��得到
Segmentation fault
(�]:有�r候把 genBlock�e的a 去掉就可以跑出�Y果的情形,�@是系�ycache住����w,�K不是inBlock真得一直存在,久了�是��被回收,千�f不要以�槭�Φ��法)
表示我��用到了不�用的����w,在�@��例子的情�r下是在genBlock�e的inBlock��翟�return的�r候就被回收了,outBlock�o法有一��合法的����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 method�e面做copying block�幼鞯脑�
1. 在Block�e如果有直接存取到self,�tself��被retain
2. 在Block�e如果取存到instance variable (�o�直接或是��accessor),�tself��被retain
3. 取存到local variable所�碛械�object�r,�@��object��被retain

�我���砜匆��自�的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主�w�e用newTitle�@����刀�不是title。�@��self就不��被retain了。
最後�一��小陷井
void (^myLog) (void); 
BOOL result ;
if(result)
    myLog = ^ {NSLog(@"YES");};

else
    myLog = ^ {NSLog(@"NO");};

myLog();

�@�雍芸赡芫����掉了,因��myLog ���w在if 或是else�Y束後就被清掉了。要�得。
要用copy�斫�Q�@�����},但要�得release。


你可能感兴趣的:(function,memory,Grand,最大的,工作量)