首页 > 代码库 > Object-C-代码块Block回顾

Object-C-代码块Block回顾

OC中的代码块是iOS4.0+ 和Mac OS X 10.6+ 引进的对C语言的扩展,用来实现匿名函数的特性。类似于其他语言脚本语言或者编程语言中的闭包或者是Lambda表达式,可能第一眼看上去很怪异,不过开发的过程中会越来越多的用到Block,还是了解多一点比较好。Block方面的内容也有很多,本文从实际使用的角度大概讲一下Block的基本概念和实践。

首先看一个苹果官网的例子:

int (^Multiply)(int, int) = ^(int num1, int num2) {    return num1 * num2;};int result = Multiply(7, 4); // Result is 28.

 上面的代码定义了一个Block,类似于C#中的委托,int表示返回类型,^是关键标示符,(int,int)是参数类型,不过需要注意的,正常的方式是将返回类型用()包裹,这里是将Block的名称包裹,网上有一个类似的图片,大家可以参考一下:

技术分享

 

Block除了能够定义参数列表、返回类型外,还能够获取被定义时的词法范围内的状态(将变量作为参数传递之后,可以修改之后返回).Block都是一些简短代码片段的封装,适用作工作单元,通常用来做并发任务、遍历、以及回调。下面看一个通知的例子:

- (void)viewDidLoad {   [super viewDidLoad];    [[NSNotificationCenter defaultCenter] addObserver:self        selector:@selector(keyboardWillShow:)        name:UIKeyboardWillShowNotification object:nil];} - (void)keyboardWillShow:(NSNotification *)notification {    // Notification-handling code goes here.}

  以上是调用addServer方法的例子,不过也可以这么写:

- (void)viewDidLoad {    [super viewDidLoad];    [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification         object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notif) {             // Notification-handling code goes here.     }];}

 苹果官网这个使用Block的例子如果第一次看可能不是那么好理解,如果仔细的看addServerName的定义发现:

- (id <NSObject>)addObserverForName:(NSString *)name object:(id)obj queue:(NSOperationQueue *)queue usingBlock:(void (^)(NSNotification *note))block NS_AVAILABLE(10_6, 4_0);

其中Block参数定义的时候是这样的:

(void (^)(NSNotification *note))block NS_AVAILABLE(10_6, 4_0)

 括号包裹起来的内容,第一个是返回值类型,之后的用用括号包裹^,之后的 话才是传递类型,基于以上的理解,可以这么写:

   void(^MyBlock)(NSNotification *)=^(NSNotification *note){        note=nil;    };    [[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardWillShowNotification                                                      object:nil queue:[NSOperationQueue mainQueue] usingBlock:MyBlock];

 Block在苹果的API文档中随处看见其身影,常见的情况任务完成时回调处理,消息监听回调处理,错误回调处理,枚举回调,视图动画、变换,排序,比如说在NSDictionary中的方法中:

- (void)enumerateKeysAndObjectsWithOptions:(NSEnumerationOptions)opts usingBlock:(void (^)(id key, id obj, BOOL *stop))block NS_AVAILABLE(10_6, 4_0);

任务完成时候的调用:

- (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.                             self.imageView.frame = cacheFrame;                             self.imageView.alpha = 1.0;                         }    }];}

 通知机制中的处理:

- (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]);    }];}

 枚举数组的时候的调用:

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);

 也可以写一个Block在截取字符串,做一些自己需要的事情:

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

  视图动画和转换中的实践:

[UIView animateWithDuration:0.2 animations:^{        view.alpha = 0.0;    } completion:^(BOOL finished){        [view removeFromSuperview];    }];

  两个视图之间的动画:

[UIView transitionWithView:containerView duration:0.2                   options:UIViewAnimationOptionTransitionFlipFromLeft                animations:^{                    [fromView removeFromSuperview];                    [containerView addSubview:toView]                }                completion:NULL];

 数组排序的实践:

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]);

 当然关于Block究竟是如何实现的,内存中是如何定义,如何保存的可以参考:http://blog.csdn.net/jasonblog/article/details/7756763

参考资料:https://developer.apple.com/library/ios/featuredarticles/Short_Practical_Guide_Blocks/

Object-C-代码块Block回顾