读书人

详解Objective-c Block运用

发布时间: 2012-07-01 13:15:00 作者: rapoo

详解Objective-c Block应用

目前只有Mac 10.6 和iOS 4有支援。Block是由一堆可行的程式成,也可以做有名字的Function (Anonymous function)

AD:

?

详解Objective-c block应用是本文要介绍的内容,主要介绍的是Objective-c block应用,不多说,先来看详细内容。

Apple在C, Objective-C, C++加上Block延申用法。目前只有Mac 10.6 和iOS 4有支援。Block是由一堆可行的程式成,也可以做有名字的Function (Anonymous function)。如果是Mac 10.6 或 iOS 4.0 之前的平台可以利用 http://code.google.com/p/plblocks/ project得以支援Block法。

Apple有一叫做GCD(Grand Central Dispach)的新功能,用在同步理(concurrency)的境下有更好的效率。Block法生的就是自於GCD,用Block包好一工作量交GCD,GCD有一宏的野可以分配CPU,GPU,Memory的下最好的定。

Block 介

Block其行和Function很像,最大的差是在可以存取同一Scope的值。

Block 成

^(入列) {行主};

Block是"^",接著是由小括所包起的列(比如 int a, int b, float c),行的主由大括包起,有名叫做block literal。行主可以用return回值,型被compiler自出。如果有列要(void)。
看列子

  1. ^(int?a)?{return?a*a;};?

是代表Block回入值的平方值(int a 就是列,return a*a; 就是行主)。得主最後要加";"因是述,而整{}最後也要要加";"因Block是物件。

用法就是

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

很怪吧。後面小括的5 被成a的入值然後由Block出5*5 = 25指定result。

有有一的方法不然每次都要?有。接下要介一叫Block Pointer的西化我的法。

Block Pointer是宣告的

回值 (^名字) (列);

直接看一列子

  1. int?(^square)?(int);? ?//?有一叫square的Block?Pointer,其所指向的Block是有一int?入和?int?出 ?
  2. square?=?^(int?a?)?{return?a*a?;};?//?Block?指定?square?

使用Block Pointer的例子

int result = square(5); // 感上不就是funtion的用法?也可以把Block Pointer成一function,比如

  1. void?myFuction(?int?(^mySquare)?(int)?);?//?function?的宣告

入一有一int入和int出的Block 型的

呼叫myFunction的候就是呼叫

  1. int?(^mySqaure)?(int)?=?^(int?a)?{return?a*a;}; ?//?先好一有的block?pointer叫mySquare ?
  2. myFunction(?mySqaure?)?;?//把mySquareblock?pointermyFunctionfunction?

或是不用block pointer 直接一block ,就

  1. myFunction(??^(int?a)?{return?a*a}?)?;?

成Objective-C method 的入值的都是要把型在前面然後加上小括,因些就要

  1. -(void)?objcMethod:(?int?(^)?(int)?)?square;?//?square?的型是?int?(^)?(int)?

文至此是不是Block有基本的? 接下我要Block相的行和特色

首先是看一下在Block面存取外部的方法

存取

1. 可以取和Block pointer同一scope的值:

  1. { ?int?outA?=?8; ?
  2. int?(^myPtr)?(int)?=?^(int?a)?{return?outA+a;}; ?//?block?面可以同一scope的outA的值 ?
  3. int?result?=?myPtr(3);?//?result?is?11 ?}?

我再看一很有趣的例子

  1. { ?int?outA?=?8; ?
  2. int?(^myPtr)?(int)?=?^(int?a)?{return?outA+a;}; ?//?block?面可以同一scope的outA的值 ?
  3. outA?=?5;?//?在呼叫myPtr之前改outA的值 ?int?result?=?myPtr(3);?//?result?的值是?11不是?8 ?
  4. }?

事上呢,myPtr在其主用到outA值的候是做了一copy的作把outA的值copy下。所以之後outA即使了新的值於myPtrcopy的值是有影到的。
?
要注意的是,指的值是的值,如果的值是一的位置,句,是pointer的,它指到的值是可以在block被改的。

  1. { ?????????NSMutableArray?*?mutableArray?=?[NSMutableArray?arrayWithObjects:@"one",@"two",@"three",nil]; ?
  2. ????????int?result?=?^(int?a)?{?[mutableArray?removeLastObject];??return?a*a;}?(5); ?????????NSLog(@"test?array?%@",?mutableArray); ?
  3. }?

原本mutableArray的值是{@"one",@"two",@"three"}在block被更改mutableArray所指向的物件後,mutableArray的值就被成{@"one",@"two"}

2. 直接存取static 的

  1. { ?static?int?outA?=?8; ?
  2. int?(^myPtr)?(int)?=?^(int?a)?{return?outA+a;}; ?//?block?面可以同一scope的outA的值 ?
  3. outA?=?5;?//?在呼叫myPtr之前改outA的值 ?int?result?=?myPtr(3);?//?result?的值是?8,因outA是static?直接反其值 ?
  4. }?

甚至可以在block面直接改outA的值比如

  1. { ?static?int?outA?=?8; ?
  2. int?(^myPtr)?(int)?=?^(int?a)?{?outA=?5;?return?outA+a;}; ?//?block?面改outA的值 ?
  3. int?result?=?myPtr(3);?//?result?的值是?8,因outA是static?直接反其值 ?}?

3. Block Variable

在某前面如果加上修字__block 的(注意block前有下底),又block variable。那在block就可以任意修改此值,值的改也可以知道。

  1. { ?????__block?int?num?=?5; ?
  2. ?????int?(^myPtr)?(int)?=?^(int?a)?{?return?num++;}; ?
  3. ????int?(^myPtr2)?(int)?=?^(int?a)?{?return?num++;}; ?????int?result?=?myPtr(0); ?
  4. ????result?=?myPtr2(0); ?}?

因myPtr和myPtr2都有用到numblock variable,最後result的值就是7

生命周期和管理

因block也是承自NSObject,所以其生命周期和的管理也就非常之重要。

block一始都是被放到stack,句其生命周期著method或function束就被回收,和一般的生命周期一。

於的管理遵循要

1. block pointer的在method或function束後就被清掉

2. 如果要保存block pointer的要用-copy指令,block pointer就被放到heap

(1)block 主用到的block variable 也被搬到heap 而有新的位置,且一更新有用到block variable 的block都指到新的位置
???
(2)一般的variable值被copy
???
(3)如果主用到的variable是object的,此object被retain, block release也被release
???
(4)block variable 用到的object是不被retain的

首先看一下例子

  1. typedef?int?(^MyBlock)(int); ??
  2. MyBlock?genBlock(); ??
  3. int?main(){ ?????????MyBlock?outBlock?=?genBlock(); ?
  4. ????????int?result?=?outBlock(5); ??
  5. ????????NSLog(@"result?is?%d",[outBlock?retainCount]?);?//?segmentation?fault ?????????NSLog(@"result?is?%d",result??); ?
  6. ?????????return?0?; ?
  7. } ?MyBlock?genBlock()?{ ?
  8. ????????int?a?=?3; ?????????MyBlock?inBlock?=?^(int?n)?{ ?
  9. ????????????????return?n*a; ?????????}; ?
  10. ????????return?inBlock?; ?}?

此程式由genBlock生的block再指定main function的outBlock,行程式得到

  1. Segmentation?fault?

(:有候把 genBlock的a 去掉就可以跑出果的情形,是系cache住,不是inBlock真得一直存在,久了是被回收,千不要以是的法)
表示我用到了不用的,在例子的情下是在genBlock的inBlock在return的候就被回收了,outBlock法有一合法的位置-retainCount就意了。

如果候需要保留inBlock的值就要用-copy指令,genBlock改成

  1. ?MyBlock?genBlock()?{ ?????????int?a?=?3; ?
  2. ????????MyBlock?inBlock?=?^(int?n)?{ ?????????????????return?n*a; ?
  3. ????????}; ?????????return?[inBlock?copy]??; ?
  4. }?

[inBlock copy]的回值就被放到heap,就可以一直使用(得要release)

行果是

  1. result?is?1 ?result?is?15?

再次提醒要得release outBlock。

如果一回[inBlock copy]的值就不再需要的候可以

  1. ?MyBlock?genBlock()?{ ?????????int?a?=?3; ?
  2. ????????MyBlock?inBlock?=?^(int?n)?{ ?????????????????return?n*a; ?
  3. ????????}; ?????????return?[[inBlock?copy]?autorelease]?; ?
  4. }?

-copy指令是了要把block stack搬到heap,autorelease是了平retainCount加到autorelease oop ,回之後等到事件束就清掉。

接下是block存取到的local variable是物件的型,然後做copy 指令

  1. MyBlock?genBlock()?{ ?????????int?a?=?3; ?
  2. ????????NSMutableString?*?myString?=?[NSMutableString?string]; ?????????MyBlock?inBlock?=?^(int?n)?{ ?
  3. ????????????????NSLog(@"retain?count?of?string?%d",[myString?retainCount]); ?????????????????return?n*a; ?
  4. ????????}; ?????????return?[inBlock?copy]?; ?
  5. }?

果印出

  1. retain?count?of?string?2?

果和上面2.3提到的一,local variable被retain了

那再2.4,在local variable前面加上__block

  1. MyBlock?genBlock()?{ ?????????int?a?=?3; ?
  2. ????????__block?NSMutableString?*?myString?=?[NSMutableString?string]; ?????????MyBlock?inBlock?=?^(int?n)?{ ?
  3. ????????????????NSLog(@"retain?count?of?string?%d",[myString?retainCount]); ?????????????????return?n*a; ?
  4. ????????}; ?????????return?[inBlock?copy]?; ?
  5. }?

行的果就是

  1. retain?count?of?string?1

Block Copying注意事

如果在Class method面做copying block作的

1. 在Block如果有直接存取到self,self被retain

2. 在Block如果取存到instance variable (直接或是accessor),self被retain

3. 取存到local variable所有的object,object被retain

我看一自的Class

  1. @interface?MyObject?:?NSObject?{ ?????????NSString?*?title; ?
  2. ????????void?(^myLog)?(NSString?*?deco); ?} ?
  3. ?-(void)?logName; ?
  4. @end ?@implementation?MyObject ?
  5. -(id)?initWithTitle:(NSString?*?)?newTitle{ ?????????if(self?=?[super?init]){ ?
  6. ????????????????title?=?newTitle; ?????????????????myLog?=?[^(NSString?*?deco)?{?NSLog(@"%@%@%@",deco,?title,?deco?);}?copy]; ?
  7. ????????} ?????????return?self; ?
  8. } ??
  9. -(void)?logName{ ??myLog(@"=="); ?
  10. } ??
  11. -(void?)?dealloc{ ??
  12. ????????[myLog?release]; ?????????[title?release]; ?
  13. ????????[super?dealloc]; ?} ?
  14. @end?

在main 使用如下

  1. MyObject?*?mObj?=?[[MyObject?alloc]?initWithTitle:@"Car"]; ?NSLog(@"retainCount?of?MyObject?is??%d",[mObj?retainCount]??); ?
  2. [mObj?logName];?

其行的果

  1. retainCount?of?MyObject?is??2?==Car==?

因在MyObject的建子myLogblock pointer用了titleinstance variable然後就retain self也就是MyObject的物件。

量不要,造成retain cycle,改善的方法是把建子改成

  1. -(id)?initWithTitle:(NSString?*?)?newTitle{ ?????????if(self?=?[super?init]){ ?
  2. ????????????????title?=?newTitle; ?????????????????myLog?=?[^(NSString?*?deco)?{?NSLog(@"%@%@%@",deco,?newTitle,?deco?);}?copy]; ?
  3. ????????} ?????????return?self; ?
  4. }?

在Block主用newTitle而不是title。self就不被retain了。

最後一小陷井

  1. void?(^myLog)?(void);? ?BOOL?result?; ?
  2. if(result) ?????myLog?=?^?{NSLog(@"YES");}; ?
  3. ?else ?
  4. ????myLog?=?^?{NSLog(@"NO");}; ??
  5. myLog();?

很可能就掉了,因myLog 在if 或是else束後就被清掉了。要得。

要用copy解,但要得release

小结:详解Objective-c block应用的内容介绍完了,希望本文对你有所帮助!更多相关内容请参考编辑推荐。

?

?

?

?

FROM:http://mobile.51cto.com/iphone-279757.htm

读书人网 >移动开发

热点推荐