objective-c block 讲解

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  copyautorelease] ;
}

-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。




//以下是个人见解:Block在IOS开发中使用还是比较频繁的,以下是我总结的一个例子:

//目标:使用Block函数实现对数组对象的遍历,并在匹配到指定字符串停止遍历

//NSArray类扩展
#import <Foundation/Foundation.h>
typedef void (^MyBlock)(NSString *str,BOOL *stop);
@interface NSArray (Bolck)

- (void)BlockTest:(MyBlock)enumerationBlock;

@end


//NSArray类扩展方法体实现
#import "NSArray+Bolck.h"

@implementation NSArray (Bolck)
//使用块读取
- (void)BlockTest:(MyBlock)enumerationBlock
{
    BOOL mybool=YES;
    for (NSString * temp in self) {
        enumerationBlock(temp,&mybool);
        if (mybool == NO)//回传值,这样极大的方便了开发者封装和灵活性
        {
            break;
        }
    }
}
@end

//main方法体
#import <Foundation/Foundation.h>
#import "NSArray+Bolck.h"


#import <Foundation/Foundation.h>
#import "NSArray+Bolck.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        NSArray * array = [[NSArray alloc]initWithObjects:@"One",@"Two",@"Three",@"Four",@"Five",nil];
        
        [array BlockTest:^(NSString *str,BOOL *stop) {
            NSLog(@"%@",str);
            if ([str isEqualToString:@"Three"]) {
                *stop = NO;
            }
        }];
        
    return 0;
    }
}
运行结果:
2014-11-18 21:06:02.008 Block[4364:207213] One
2014-11-18 21:06:02.009 Block[4364:207213] Two
2014-11-18 21:06:02.010 Block[4364:207213] Three
Program ended with exit code: 0

总结:在IOS开发中,一般Block的使用主要就是为了对象调用函数时,看该函数内部是否满足某种条件,若满足则将执行结果当做参数传递给Block函数,用来调用该Block方法体!以下是一个IOS使用Block方法的函数:

typedef void (^ALAssetsLibraryGroupsEnumerationResultsBlock)(ALAssetsGroup *group, BOOL *stop);
typedef void (^ALAssetsLibraryAccessFailureBlock)(NSError *error);


- (void)enumerateGroupsWithTypes:(ALAssetsGroupType)types usingBlock:(ALAssetsLibraryGroupsEnumerationResultsBlock)enumerationBlock failureBlock:(ALAssetsLibraryAccessFailureBlock)failureBlock;
该方法体来源与函数库:这个函数的用途就是枚举手机内的所有相册,每枚举到一个就会调用ALAssetsLibraryGroupsEnumerationResultsBlock块函数,这极大的方便开发者在函数块满足条件时,实现自己想要实现的代码,增加灵活性!

转载自:http://fei263.blog.163.com/blog/static/9279372420113193523828/

你可能感兴趣的:(ios,oc,block)