【转】blocks实践指南

本文详细介绍了在iOS开发中使用Blocks的多种场景,包括作为回调处理NSNotification、在系统框架API中作为completion handlers、error handlers、notification handlers等,以及在concurrency中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.sina.com.cn/s/blog_67419c420100vmkt.html

 

1.为什么要使用blocks
将一个blocks作为函数或者方法的参数传递,可以使函数或者方法在恰当的点实现回调。以各种NSNotification类为例子,传统的方法是一个对象添加自己作为此通知的观察者,实现处理接到通知应该调用的方法(通过addObserver....)。
如下:
- (void)viewDidLoad { 
 [super viewDidLoad]; 
 [[NSNotificationCenter defaultCenter] addObserver:self 
 selector:@selector(keyboardWillShow:) 
 name:UIKeyboardWillShowNotification object:nil]; 
} 
 
- (void)keyboardWillShow:(NSNotification *)notification { 
 // Notification-handling code goes here. 
} 
然而通过方法  addObserverForName:object:queue:usingBlock: 我们也可以实现对通知的监控。
实现如下:
- (void)viewDidLoad { 
 [super viewDidLoad]; 
 [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification 
 object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) { 
 // Notification-handling code goes here. 
 }]; 
} 
2.系统框架API中的blocks
另一个使用blocks的明显动机就是系统框架中提供了很多方法和函数用blocks作为参数。一般都存在于:
completion handlers,notification handlers,error handlers,enumeration,view animation and transitions,sorting 中,下面讲详细介绍。
(1)completion and Error handlers
     completion handlers是回调,其允许当框架方法或者函数完成任务时,在进行一些处理。多数情况下,用completion handler去free state 或者更新用户界面。很多框架方法让我们用blocks实现completion handlers,而不是代理方法或者notification handlers。
    UIView类有很多关于animation和view transitions的方法有completion handler block 参数。下面是 animateWithDuration:animations:completion: 方法的一个实现例子。
- (IBAction)animateView:(id)sender { CGRect cacheFrame = self.imageView.frame; [UIView animateWithDuration:1.5 animations:^{ CGRect newFrame = self.imageView.frame; newFrame.origin.y = newFrame.origin.y + 150.0; self.imageView.frame = newFrame; self.imageView.alpha = 0.2; } completion:^ (BOOL finished) { if (finished) { // Revert image view to original. sleep(3); self.imageView.frame = cacheFrame; self.imageView.alpha = 1.0; } }]; } 
一些框架方法有error handlers,和completion handlers很相似。这些方法当其因为一些错误条件不能完成自己的任务的时候,调用这些error handlers blocks。我们典型的实现这些error handlers去通知用户出现错误。
(2)Notification handlers
   NSNotificationCenter的 addObserverForName:object:queue:usingBlock:方法让我们去实现一个通知的handler去建立一个observation。下面是一个例子:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 
 opQ = [[NSOperationQueue alloc] init]; 
 [[NSNotificationCenter defaultCenter] addObserverForName:@"CustomOperationCompleted" 
 object:nil queue:opQ 
 usingBlock:^(NSNotification *notif) { 
 NSNumber *theNum = [notif.userInfo objectForKey:@"NumberOfItemsProcessed"]; 
 NSLog(@"Number of items processed: %i", [theNum intValue]); 
 }]; 
} 
上面的方法要求传入一个NSOperationQueue实例,因此应用程序可以指定执行block handler 的execution context。
(3)Enumeration
   Foundation framework的集合类(NSArray ,NSDictionary, NSSet 和 NSIndexSet)声明了一些方法,可以用blocks来枚举整个集合,其实等价与下代码段:
for (id item in collection) { 
 // Code to operate on each item in turn. 
} 
    大概有两种形式。第一种方法名字以enumerate开始,没有返回值。
    第二种方法 block参数之前的名字为passingTest,这种方法返回整数或者一个NSIndexSet对象。这种方法的block一般是对迭代的每一个元素进行一个test,当test通过时返回YES。返回整数或者一个标识通过test的对象的集合。
   下面的代码对NSArray分别做了实例。一个方法的block返回数组中每个string有特定前缀的集合。
NSString *area = @"Europe"; 
NSArray *timeZoneNames = [NSTimeZone knownTimeZoneNames]; 
NSMutableArray *areaArray = [NSMutableArray arrayWithCapacity:1]; 
NSIndexSet *areaIndexes = [timeZoneNames indexesOfObjectsWithOptions:NSEnumerationConcurrent 
 passingTest:^(id obj, NSUInteger idx, BOOL *stop) { 
 NSString *tmpStr = (NSString *)obj; 
 return [tmpStr hasPrefix:area]; 
}]; 
 
NSArray *tmpArray = [timeZoneNames objectsAtIndexes:areaIndexes]; 
[tmpArray enumerateObjectsWithOptions:NSEnumerationConcurrent|NSEnumerationReverse 
 usingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 
 [areaArray addObject:[obj substringFromIndex:[area length]+1]]; 
}]; 
NSLog(@"Cities in %@ time zone:%@", area, areaArray); 
    尽管NSString类不属于集合,但是它也有两个有block参数的方法,为 enumerateSubstringsInRange:options:usingBlock:  enumerateLinesUsingBlock:。第一个方法的枚举单元可以是行,段,词,句,等等,但是第二个方法的就只是行。
下面的代码是使用block去匹配substring。
NSString *musician = @"Beatles"; 
NSString *musicDates = [NSString stringWithContentsOfFile: 
 @"/usr/share/calendar/calendar.music" 
 encoding:NSASCIIStringEncoding error:NULL]; 
[musicDates enumerateSubstringsInRange:NSMakeRange(0, [musicDates length]-1) 
 options:NSStringEnumerationByLines 
 usingBlock:^(NSString *substring, NSRange substringRange, NSRange enclosingRange, BOOL *stop) { 
 NSRange found = [substring rangeOfString:musician]; 
 if (found.location != NSNotFound) { 
 NSLog(@"%@", substring); 
 } 
 }]; 
(4)view animation 和 transitions
ios4.0之后UIView类引入了一些用于动画和view transitions的带block参数的方法。block参数分两类:
    block用于改变view的属性以完成动画。
    completion handlers。
下面的代码讲述了 animateWithDuration:animations:completion:方法的用法。
[UIView animateWithDuration:0.2 animations:^{ 
 view.alpha = 0.0; 
 } completion:^(BOOL finished){ 
 [view removeFromSuperview]; 
 }]; 
这个动画就是让view逐渐消失,然后从父视图上移除。
  方法 transitionWithView:duration:options:animations:completion:用于两个view的transitions,包括flips和curls。
下面的代码段实现了两个views 的flip transitions。
[UIView transitionWithView:containerView duration:0.2 
 options:UIViewAnimationOptionTransitionFlipFromLeft animations:^{ 
 [fromView removeFromSuperview]; 
 [containerView addSubview:toView] 
 } 
 completion:NULL]; 
(5)sorting
foundation framework声明了NSComparator类型用于比较两个元素。
typedef NSComparisonResult (^NSComparator)(id obj1, id obj2); 
NSComparator是一个block类型,用于两个对象的比较,然后返回一个NSComparisonResult值。下面是一个例子:
NSArray *stringsArray = [NSArray arrayWithObjects: 
 @"string 1", 
 @"String 21", 
 @"string 12", 
 @"String 11", 
 @"String 02", nil]; 
static NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch | 
 NSWidthInsensitiveSearch | NSForcedOrderingSearch; 
NSLocale *currentLocale = [NSLocale currentLocale]; 
NSComparator finderSort = ^(id string1, id string2) { 
 NSRange string1Range = NSMakeRange(0, [string1 length]); 
 return [string1 compare:string2 options:comparisonOptions range:string1Range locale:currentLocale]; 
}; 
NSLog(@"finderSort: %@", [stringsArray sortedArrayUsingComparator:finderSort]); 
3.block 和concurrency
   block封装了一段代码,可以异步执行。基于这一事实,块可以用在GCD和NSOperationQueue上面。

   GCD函数dispatch_sync和函数dispatch_async的第二个参数就是用block。 

转载于:https://www.cnblogs.com/yencain/articles/2482605.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值