[精通Objective-C]块(block)

来源:互联网 发布:python中定义矩阵 编辑:程序博客网 时间:2024/06/03 09:26

[精通Objective-C]块(block)

参考书籍:《精通Objective-C》【美】 Keith Lee

目录

  • 精通Objective-C块block
    • 目录
    • 块的语法
    • 块的词汇范围
    • 块的内存管理
    • 块的使用
      • 使用块为数组排序
      • 使用块的并行编程方式

块的语法

块是一个实现的闭包,一个允许访问其常规范围之外变量的函数。此外,一个Objective-C块实际上就是一个对象,它是NSObject类的子类,拥有NSObject类的相关属性。

块的声明:

        int (^oneParamBlock)(int); // 声明一个名为oneParamBlock的块,该块接收一个int型参数,返回值也是int型的        void (^twoParamBlock)(int,int); // 接收两个int型参数,无返回值        void (^twoParamBlock2)(int parm1, int parm2); // 声明中可以含有参数名称        int (^noParamBlock)(void); // 没有参数需要写上void,不能省略

块的定义和调用:

        // 将块常量赋值给之前声明的块(参数与返回值类型均需一致)        oneParamBlock = ^(int addend){            return addend + 1;        };        // 将块的声明和定义组合到一起(如果块常量没有参数,可以省略)        void (^noParamBlock2)(void) = ^{            NSLog(@"Hello,World!");        };        // 块的调用        int value = oneParamBlock(5);        NSLog(@"%d",value);        // 定义并调用块表达式        ^(NSString *user){            NSLog(@"Greetings,%@!",user);        }(@"Earthing");

将块常量表达式用作调用方法的参数:

// 创建一个名为AdderBlock的块类型用作方法中的参数类型typedef int (^AdderBlock)(int);@interface Calculator : NSObject-(int)process:(int)count withBlock:(AdderBlock)adder;@end@implementation Calculator-(int)process:(int)count withBlock:(AdderBlock)adder{    return adder(count);}@end
        Calculator *clac = [Calculator new];        int result = [clac process:2 withBlock:^int(int addend) {            return addend + 1;        }];        NSLog(@"%d",result);

块的词汇范围

局部变量的声明需要放在使用该局部变量的块之前。默认情况下,块常量表达式中不能对局部变量进行修改,使用__block修改符可以将这些变量切换为读写模式,但__block修改符不能与auto、register和static组合使用。

        int myVar = 10;        void (^logValueBlock)(void) = ^{            NSLog(@"Variable value = %d", myVar);        };        logValueBlock();        __block int myVar2 = 10;        void(^intBlock)(int) = ^(int amount){            myVar2 += amount;            NSLog(@"New value = %d", myVar2);        };        intBlock(5);

块的内存管理

在运行程序时,块常量表达式会获得栈内存,因而会拥有与局部变量相同的生命周期。因此它们必须被复制到永久存储区域(即堆)中,才能定义它们的范围之外使用。例如,如果你想要从方法获得类型为块常量的返回值或者存储块常量,就必须将块复制到堆中并在不再使用它们时释放这些块。

在MRR内存管理方式中,块的copy和release需要达到平衡

        void (^greetingBlock)(void);        {            greetingBlock = [^{                NSLog(@"Hello,World!");            } copy];        }        greetingBlock();        [greetingBlock release]; // 释放块,防止内存泄漏

而在ARC内存管理方式中,编译器会自动执行块的复制和释放操作

块的使用

下面是两个使用块的例子:

使用块为数组排序

#import <Foundation/Foundation.h>#include <stdlib.h>#define ArrayElements 10int main(int argc, const char * argv[]) {    @autoreleasepool {        // 创建一个含有随机数值(0~99)的数组        NSMutableArray *numbers = [NSMutableArray arrayWithCapacity: ArrayElements];        for (int elem = 0; elem < ArrayElements; elem++) {            unsigned int value = arc4random() % 100;            [numbers addObject:[NSNumber numberWithUnsignedInt:value]];        }        NSLog(@"Values:%@",numbers); // 记录未排序的数值        // 以升序方式为数组数值排序        [numbers sortUsingComparator:^(id obj1, id obj2){            if ([obj1 integerValue] > [obj2 integerValue]) {                return (NSComparisonResult)NSOrderedDescending;            }            if ([obj1 integerValue] < [obj2 integerValue]) {                return (NSComparisonResult)NSOrderedAscending;            }            return (NSComparisonResult)NSOrderedSame;        }];        NSLog(@"Values:%@",numbers); //记录未排序的数值    }    return 0;}

使用块的并行编程方式

#import <Foundation/Foundation.h>#define YahooURL  @"http://www.yahoo.com/index.html"#define ApressURL @"http://www.apress.com/index.html"typedef void (^DownloadURL)(void);// 获取用于下载URL的块DownloadURL getDownloadURL(NSString *url){    NSString *urlString = url;    return ^{        // 下载URL        NSDate *startTime = [NSDate date];        NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlString]];        NSError *error;        // 注意,NSURLConnection在iOS9中已被废除,推荐使用NSURLSession,后面有NSURLSession的使用方法        NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];        if (data == nil) {            NSLog(@"Error loading request %@",[error localizedDescription]);        }        else{            NSDate *endTime = [NSDate date];            NSTimeInterval timeInterval = [endTime timeIntervalSinceDate:startTime];            NSLog(@"Time taken to download %@ = %f seconds", urlString, timeInterval);        }    };}int main(int argc, const char * argv[]) {    @autoreleasepool {        // 创建任务请求        dispatch_queue_t queue1 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);        dispatch_queue_t queue2 = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);        // 创建任务分组        dispatch_group_t group = dispatch_group_create();        // 获取度量的当前时间        NSDate *startTime = [NSDate date];        // 创建并分派异步任务        dispatch_group_async(group, queue1, getDownloadURL(YahooURL));        dispatch_group_async(group, queue2, getDownloadURL(ApressURL));        // 等待,直到分组中的所有任务完成为止        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);        // 为并行操作和日志检索时间信息        NSDate *endTime = [NSDate date];        NSTimeInterval timeInterval = [endTime timeIntervalSinceDate:startTime];        NSLog(@"Time taken to download URLs concurrently = %f seconds", timeInterval);    }    return 0;}

使用NSURLSession:

        // NSURLSession在命令行程序中可能无法正常使用,可以在iOS环境下调试        NSURLSession *session = [NSURLSession sharedSession];        NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {            NSLog(@"123");            if (data == nil) {                NSLog(@"Error loading request %@",[error localizedDescription]);            }            else{                NSDate *endTime = [NSDate date];                NSTimeInterval timeInterval = [endTime timeIntervalSinceDate:startTime];                NSLog(@"Time taken to download %@ = %f seconds", urlString, timeInterval);            }        }];        [dataTask resume];

运行结果:

2016-07-14 16:03:50.780 BlockConcurrentTasks[20262:170183] Time taken to download http://www.apress.com/index.html = 1.259164 seconds2016-07-14 16:03:54.485 BlockConcurrentTasks[20262:170182] Time taken to download http://www.yahoo.com/index.html = 4.965020 seconds2016-07-14 16:03:54.486 BlockConcurrentTasks[20262:170152] Time taken to download URLs concurrently = 4.965577 seconds

可以看出并行方式执行任务的时间比以异步方式所消耗的时间更少。

2 0
原创粉丝点击