欢迎访问移动开发之家(rcyd.net),关注移动开发教程。移动开发之家  移动开发问答|  每日更新
页面位置 : > > > 内容正文

[精通Objective-C]块(block),objective-cblock

来源: 开发者 投稿于  被查看 34225 次 评论:243

[精通Objective-C]块(block),objective-cblock


[精通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 10

int 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 seconds
2016-07-14 16:03:54.485 BlockConcurrentTasks[20262:170182] Time taken to download http://www.yahoo.com/index.html = 4.965020 seconds
2016-07-14 16:03:54.486 BlockConcurrentTasks[20262:170152] Time taken to download URLs concurrently = 4.965577 seconds

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

相关文章

    暂无相关文章

用户评论