ios里面的blocks学习
来源:互联网 发布:兄弟连 李明 linux 编辑:程序博客网 时间:2024/05/21 08:00
转载请注明,谢谢。
Ios4已经直接支持blocks,很有必要学习一下。
在ios,blocks是对象,它封装了一段代码,这段代码可以在任何时候执行。Blocks可以作为函数参数或者函数的返回值,而其本身又可以带输入参数或返回值。它和传统的函数指针很类似,但是有区别:blocks是inline的,并且它对局部变量是只读的。
Blocks的定义:
int (^Multiply)(int,int) = ^(int num1,int num2) {return num1 * num2;};
定义了一个Multiply的blocks对象,它带有两个int参数,返回int。等式右边就是blocks的具体实现,注意{}blocks体里的;。
Blocks可以访问局部变量,但是不能修改。
int multiplier = 7;
int (^myBlock)(int) = ^(int num) {
multiplier ++;//编译报错
return num * multiplier;
};
如果要修改就要加关键字:__block
__blockint multiplier =7;
int (^myBlock)(int) = ^(int num) {
multiplier ++;//这样就可以了
return num * multiplier;
};
作为函数的参数,blocks某种意义上替代了回调函数或者delegate。当函数调用了,假设某个事件触发,这时blocks里的内容就会运行。这样有利于代码的整合和阅读,你不需要到处去实现委托方法了。
系统API中已经有很多支持blocks参数了
· Completionhandlers
· Notificationhandlers
· Errorhandlers
· Enumeration
· Viewanimation and transitions
· Sorting
例如:
[UIViewanimateWithDuration:(NSTimeInterval)durationanimations:(void(^)())animations]
集合体中也可以运用blocks。枚举一个数组时我们通常:
for (id obj in Array);
现在,
NSString *area = @"Europe";
NSArray *timeZoneNames = [NSTimeZoneknownTimeZoneNames];
NSMutableArray *areaArray =[NSMutableArrayarrayWithCapacity:1];
NSIndexSet *areaIndexes =[timeZoneNamesindexesOfObjectsWithOptions:NSEnumerationConcurrent
passingTest:^(id obj,NSUInteger idx,BOOL *stop) {
NSString *tmpStr = (NSString *)obj;
return [tmpStrhasPrefix:area];
}];
NSArray *tmpArray = [timeZoneNamesobjectsAtIndexes:areaIndexes];
[tmpArray enumerateObjectsWithOptions:NSEnumerationConcurrent|NSEnumerationReverse
usingBlock:^(id obj,NSUInteger idx,BOOL *stop) {
[areaArrayaddObject:[obj substringFromIndex:[arealength]+1]];
}];
NSLog(@"Cities in %@ timezone:%@", area, areaArray);
在blocks中obj就是数组中的每个成员,我们就可以在blocks内对每个对象进行处理。再比如:
NSMutableArray *mArray = [NSMutableArrayarrayWithObjects:@"a",@"b",@"abc",nil];
NSMutableArray *mArrayCount= [NSMutableArrayarrayWithCapacity:1];
[mArray enumerateObjectsWithOptions:NSEnumerationConcurrentusingBlock: ^(id obj,NSUInteger idx,BOOL *stop){
[mArrayCount addObject:[NSNumbernumberWithInt:[objlength]]];
}];
NSLog(@"%@",mArrayCount);
你会发现,这样写代码更容易读懂。
最后,看一个排序的例子:
NSArray *stringsArray = [NSArrayarrayWithObjects:
@"string1",
@"String21",
@"string12",
@"String11",
@"String02",nil];
staticNSStringCompareOptionscomparisonOptions =NSCaseInsensitiveSearch |NSNumericSearch |
NSWidthInsensitiveSearch|NSForcedOrderingSearch;
NSLocale *currentLocale = [NSLocalecurrentLocale];
NSComparator finderSort =^(idstring1,id string2) {
NSRange string1Range =NSMakeRange(0, [string1length]);
return [string1compare:string2options:comparisonOptionsrange:string1Rangelocale:currentLocale];
};
NSLog(@"finderSort: %@",[stringsArraysortedArrayUsingComparator:finderSort]);
结果:finderSort:(
"string 1",
"String 02",
"String 11",
"string 12",
"String 21"
)
之前简单的纪录过关于block的一些知识点,最近有人在回帖问了个问题。顺便温习了下,感觉内容放在现在有点单薄。
于是结合提问,把相关的东西整理一下。
问题简单的说:block内局部变量无法修改,但为什么可以添加数组?比如:
NSMutableArray *mArray = [NSMutableArray arrayWithObjects:@"a",@"b",@"abc",nil];NSMutableArray *mArrayCount = [NSMutableArray arrayWithCapacity:1];[mArray enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock: ^(id obj,NSUInteger idx, BOOL *stop){ [mArrayCount addObject:[NSNumber numberWithInt:[obj length]]]; }];
我觉得这个问题和block关系不大,根本是概念没有理清:
- OC中数组等对象,是一个指针
- 数组添加/删除对象,指针本身并没有变化
因此,除非在block里对数组进行赋值,否则任何操作都是可行的。
下面总结下,block下变量的访问权限:
- 相同作用域下,局部变量在block内是只读的
- 相同作用域下,带__block修饰的变量,在block内是可读写的
- 静态变量和全局变量在block内是可读写的。
当block内使用了局部变量时,block会在栈上保存一份局部变量(block都是存储在栈上的),保存的变量在block里是一个常量,所以不能修改。
若是OC中的对象,blcok会retain,等执行完毕后再release。
如果有带__block的变量,那么block就可以对此变量进行修改。由此可见,带__block的变量不是线程安全的。iOS中,我们经常通过设置request的completionBlock来简化代码时,就需要注意到这一点。
block保存相同作用域下局部变量的能力和JS中匿名函数的闭包特性有点类似,看一个例子:
typedef void (^TestBlock) (void); int val = 20; TestBlock block1 = ^{ NSLog (@"%d", val); }; val = 50; TestBlock block2 = ^{ NSLog (@"%d", val); }; val = 5; TestBlock block3 = ^{ NSLog (@"%d", val); }; block1(); block2(); block3(); //output: 20 50 5
仿照大多数js书上会举的例子,我们还有:
TestBlock block[10]; for (int i = 0; i < 10; i ++) { block[i] = ^{NSLog(@"the %d",i);}; block[i](); } NSLog(@"After:\n"); for (int i = 0; i < 10; i++) { block[i](); }
所以要注意block的作用域。
block本质上是对象,所以在OC中不得不提到内存管理。
int localInt = 100; __block int blockInt = 0; TestBlock blockPtr = ^{ blockInt += localInt; };
如上的代码,所有的变量都存储在栈上。假如我们复制block:
TestBlock blockCopy = block_copy(blockPtr);
对于blockCopy,它也保存了局部变量localInt,但是localInt被“复制”后存储在堆里。同样的,blockInt也被“复制”存储在堆里。
但是在栈上的blockInt会生成一个指针,指向新复制到堆上的blockInt。换言之,blockInt此时是一个“共享”变量。虽然使用copy的场景并不多见,但也是需要注意的地方。
另外,Apple的文档里还提到:
如果block访问到了类的实例变量,那么block会retain self本身。
因为:
var : self->var
所以self会被retain,这种情况下有可能发生循环引用而使得内存不能释放,需要小心。
有不对的地方,欢迎指正。
- ios里面的blocks学习
- 【IOS学习】之八、Blocks的实现
- ios学习--blocks programming
- 【IOS学习】之九、Blocks的实现续
- 【IOS学习】之九、Blocks的实现再续
- iOS中Blocks的介绍
- iOS中Blocks的介绍
- 【ios学习】之七、Blocks简介
- IOS Blocks
- [ios]blocks
- 在Code::Blocks里面设置SDL工程的方法
- iOS Blocks与Dispatch Queue的使用
- ios--Blocks与Dispatch Queue的使用
- iOS里面的委托
- iOS 里面的addchildController
- blocks学习
- blocks 学习
- Blocks 学习
- GCD之dispatch queue
- ubuntu 只剩下一个桌面 3D失败Unity左侧启动器栏和顶部菜单栏消失
- Openstack Swift Quotas初探(Grizzly)
- Android 系统调用
- C语言学习路线
- ios里面的blocks学习
- JavaScript 拖放效果
- Surface、SurfaceView、SurfaceHolder及SurfaceHolder.Callback之间的关系
- 程序员的奋斗史(十八)——人活着,只是一种态度
- 应用多入口
- test命令和[...]
- UVa10324 - Zeros and Ones
- debian下给用户添加权限
- 百度地图API Android SDK开发笔记二实现公交车查询