详解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)。
看列子
- ^(int?a)?{return?a*a;};?
是代表Block回入值的平方值(int a 就是列,return a*a; 就是行主)。得主最後要加";"因是述,而整{}最後也要要加";"因Block是物件。
用法就是
- int?result?=?^(int?a)?{return?a*a;}?(5);?
很怪吧。後面小括的5 被成a的入值然後由Block出5*5 = 25指定result。
有有一的方法不然每次都要?有。接下要介一叫Block Pointer的西化我的法。
Block Pointer是宣告的
回值 (^名字) (列);
直接看一列子
- int?(^square)?(int);? ?//?有一叫square的Block?Pointer,其所指向的Block是有一int?入和?int?出 ?
- square?=?^(int?a?)?{return?a*a?;};?//?Block?指定?square?
使用Block Pointer的例子
int result = square(5); // 感上不就是funtion的用法?也可以把Block Pointer成一function,比如
- void?myFuction(?int?(^mySquare)?(int)?);?//?function?的宣告
入一有一int入和int出的Block 型的
呼叫myFunction的候就是呼叫
- int?(^mySqaure)?(int)?=?^(int?a)?{return?a*a;}; ?//?先好一有的block?pointer叫mySquare ?
- myFunction(?mySqaure?)?;?//把mySquareblock?pointermyFunctionfunction?
或是不用block pointer 直接一block ,就
- myFunction(??^(int?a)?{return?a*a}?)?;?
成Objective-C method 的入值的都是要把型在前面然後加上小括,因些就要
- -(void)?objcMethod:(?int?(^)?(int)?)?square;?//?square?的型是?int?(^)?(int)?
文至此是不是Block有基本的? 接下我要Block相的行和特色
首先是看一下在Block面存取外部的方法
存取
1. 可以取和Block pointer同一scope的值:
- { ?int?outA?=?8; ?
- int?(^myPtr)?(int)?=?^(int?a)?{return?outA+a;}; ?//?block?面可以同一scope的outA的值 ?
- int?result?=?myPtr(3);?//?result?is?11 ?}?
我再看一很有趣的例子
- { ?int?outA?=?8; ?
- int?(^myPtr)?(int)?=?^(int?a)?{return?outA+a;}; ?//?block?面可以同一scope的outA的值 ?
- outA?=?5;?//?在呼叫myPtr之前改outA的值 ?int?result?=?myPtr(3);?//?result?的值是?11不是?8 ?
- }?
事上呢,myPtr在其主用到outA值的候是做了一copy的作把outA的值copy下。所以之後outA即使了新的值於myPtrcopy的值是有影到的。
?
要注意的是,指的值是的值,如果的值是一的位置,句,是pointer的,它指到的值是可以在block被改的。
- { ?????????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被更改mutableArray所指向的物件後,mutableArray的值就被成{@"one",@"two"}
2. 直接存取static 的
- { ?static?int?outA?=?8; ?
- int?(^myPtr)?(int)?=?^(int?a)?{return?outA+a;}; ?//?block?面可以同一scope的outA的值 ?
- outA?=?5;?//?在呼叫myPtr之前改outA的值 ?int?result?=?myPtr(3);?//?result?的值是?8,因outA是static?直接反其值 ?
- }?
甚至可以在block面直接改outA的值比如
- { ?static?int?outA?=?8; ?
- int?(^myPtr)?(int)?=?^(int?a)?{?outA=?5;?return?outA+a;}; ?//?block?面改outA的值 ?
- int?result?=?myPtr(3);?//?result?的值是?8,因outA是static?直接反其值 ?}?
3. Block Variable
在某前面如果加上修字__block 的(注意block前有下底),又block variable。那在block就可以任意修改此值,值的改也可以知道。
- { ?????__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都有用到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的
首先看一下例子
- 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生的block再指定main function的outBlock,行程式得到
- Segmentation?fault?
(:有候把 genBlock的a 去掉就可以跑出果的情形,是系cache住,不是inBlock真得一直存在,久了是被回收,千不要以是的法)
表示我用到了不用的,在例子的情下是在genBlock的inBlock在return的候就被回收了,outBlock法有一合法的位置-retainCount就意了。
如果候需要保留inBlock的值就要用-copy指令,genBlock改成
- ?MyBlock?genBlock()?{ ?????????int?a?=?3; ?
- ????????MyBlock?inBlock?=?^(int?n)?{ ?????????????????return?n*a; ?
- ????????}; ?????????return?[inBlock?copy]??; ?
- }?
[inBlock copy]的回值就被放到heap,就可以一直使用(得要release)
行果是
- result?is?1 ?result?is?15?
再次提醒要得release outBlock。
如果一回[inBlock copy]的值就不再需要的候可以
- ?MyBlock?genBlock()?{ ?????????int?a?=?3; ?
- ????????MyBlock?inBlock?=?^(int?n)?{ ?????????????????return?n*a; ?
- ????????}; ?????????return?[[inBlock?copy]?autorelease]?; ?
- }?
-copy指令是了要把block stack搬到heap,autorelease是了平retainCount加到autorelease oop ,回之後等到事件束就清掉。
接下是block存取到的local variable是物件的型,然後做copy 指令
- 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]?; ?
- }?
果印出
- retain?count?of?string?2?
果和上面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]?; ?
- }?
行的果就是
- 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
- @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 使用如下
- MyObject?*?mObj?=?[[MyObject?alloc]?initWithTitle:@"Car"]; ?NSLog(@"retainCount?of?MyObject?is??%d",[mObj?retainCount]??); ?
- [mObj?logName];?
其行的果
- retainCount?of?MyObject?is??2?==Car==?
因在MyObject的建子myLogblock pointer用了titleinstance variable然後就retain self也就是MyObject的物件。
量不要,造成retain cycle,改善的方法是把建子改成
- -(id)?initWithTitle:(NSString?*?)?newTitle{ ?????????if(self?=?[super?init]){ ?
- ????????????????title?=?newTitle; ?????????????????myLog?=?[^(NSString?*?deco)?{?NSLog(@"%@%@%@",deco,?newTitle,?deco?);}?copy]; ?
- ????????} ?????????return?self; ?
- }?
在Block主用newTitle而不是title。self就不被retain了。
最後一小陷井
- void?(^myLog)?(void);? ?BOOL?result?; ?
- if(result) ?????myLog?=?^?{NSLog(@"YES");}; ?
- ?else ?
- ????myLog?=?^?{NSLog(@"NO");}; ??
- myLog();?
很可能就掉了,因myLog 在if 或是else束後就被清掉了。要得。
要用copy解,但要得release
小结:详解Objective-c block应用的内容介绍完了,希望本文对你有所帮助!更多相关内容请参考编辑推荐。
?
?
?
?
FROM:http://mobile.51cto.com/iphone-279757.htm