[精通Objective-C]块(block)

2023-11-01

[精通Objective-C]块(block)

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

目录

块的语法

块是一个实现的闭包,一个允许访问其常规范围之外变量的函数。此外,一个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

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[精通Objective-C]块(block) 的相关文章

  • Xcode 警告“未使用属性访问结果 - getter 不应用于产生副作用”

    当我调用本地例程时 我收到此警告 我的代码是这样的 void nextLetter NSLog s FUNCTION currentLetter if currentLetter gt letters count 1 currentLett
  • iOS 静态与动态框架说明

    我不得不承认 随着 iOS 8 的发布 我对 iOS 中的动态框架和静态框架有点困惑 我正在寻找一种方法来分发我创建的库 并且我需要支持 iOS 7 及更高版本 注意 这将是一个专有框架 我不能使用 cocoa pods 也不能分发源代码
  • 使用 JSONDecoder 解码的对象的打印输出出现问题

    我正在尝试快速解码 JSON 字符串 但在解码后访问属性时遇到一些奇怪的问题 这是我从本地存储的 JSON 文件检索的 JSON 文件的内容 word a usage partOfSpeech determiner 这是访问 JSON 文件
  • 如何将 UIImage 和 UILabel 合并为一张图像并保存

    我有 2 个 UILabels 和 2 个图像 我需要将它们合并到一个 UIImage 中进行保存 我知道我可以用屏幕截图来做到这一点 但我的主图像是圆形的 所以如果我对其进行校正 它仍然会显示锐利的边缘 我可以这样做来组合图像 CGSiz
  • 如何缩放 CAShapeLayer

    我很快就成功制作了动画bezier path它包含在一个CAShapeLayer 我唯一的问题是将其实现到其他屏幕尺寸上 有谁知道我如何扩展CAShapeLayer里面有路径吗 即使其变为原始大小的一半 使用这个函数 var shapela
  • 在 UIPickerView 中选择某些内容时发生某些事情

    我正在致力于创建一个使用 UIPickerView 的应用程序 我制作了视图 但我试图让某个按钮改变它的功能 请帮忙 UIPickerView 和许多其他控件使用委托模式来通知您发生的事件 要使用它添加
  • Vimeo 播放器 JS API 在 iOS 中无法运行

    我正在尝试使用 API 来播放视频 但只有在 iOS 中单击播放器中的播放按钮后它才有效 在桌面版和 Android 版 Chrome 中 它运行良好 http codepen io bdougherty pen JgDfm http co
  • Google 地图 ios:Mapview 路线垂直折线始终指向位置箭头的北部或顶部

    我已经在我的应用程序中实现了 Google Maps IOS 的基本功能 我必须将地图视图的方位设置为始终指向顶部或北部 我需要 如果我点击导航按钮 地图视图应该动画到位置箭头顶部 就像谷歌地图 ios 应用程序一样 箭头应始终固定并指向北
  • 保护移动连接 - 存储秘密和密钥

    感谢您花时间阅读本文 我是一名年轻的开发人员 在 Web 项目和服务器端编码方面拥有一些专业经验 但我现在正在构建我的第一个移动应用程序 经过在线深入研究后 我还没有能够澄清我关于保护移动应用程序数据传输的一些问题 这是我认为我理解正确的
  • 在 iPhone 的日期选择器中插入空白值

    我有一个日期选择器 使用操作表显示 我想在日期选择器中插入一个空白值并将其设置为默认值 它应该仅根据用户选择而改变 这可能吗 如果是的话怎么办 感谢所有宝贵的建议 UIDatePicker 仅支持某些模式 并且不允许这种自定义 将空白或自定
  • Xcode 11 向后兼容性:“UIWindowScene 仅在 iOS 13 或更高版本中可用”

    在 Xcode 11 中 我从 Single View App 模板创建了一个新的应用程序项目 我希望这个应用程序能够在 iOS 12 和 iOS 13 中运行 但是当我将部署目标切换到 iOS 12 时 我收到了很多类似这样的错误消息 U
  • 继承属性,从 readonly 继承的属性中读写时不会合成 setter

    我在使用属性时发现了一个奇怪的行为 该属性被继承为只读 然后在继承的类中重新声明为读写 In A h interface A NSObject property nonatomic strong readonly NSObject some
  • 高度在 IOS (iphone) 上无法正常工作

    我已经创建了this https codepen io salman15 project live DWbWpo Codepen 上的网站 在尝试使其响应所有平台时 我遇到了问题 看起来单个 div 覆盖了整个页面 仅在 IOS 上 并且并
  • 从 AppDelegate 启动 ViewController

    我有一个自定义 URL 方案 我想打开某个ViewController当我访问此 URL 时 这不是根 我已经能够做到这一点 剩下的就是推动这一点ViewController进入navigationController来自AppDelega
  • 有没有办法直观地看到精灵套件的 SKPhysicsbody 边界线?

    我在用bodyWithPolygonFromPath定义物理体的体积 我使用http dazchong com spritekit http dazchong com spritekit 获取所需的路径 但路径似乎不正确 我希望查看物理体路
  • 如何使用 AVCaptureVideoPreviewLayer 从相机应用程序实现 2 倍变焦

    我的应用程序中有一个 AVCaptureVideoPreviewLaye 它运行良好 并且显示与相机应用程序相同的预览视频 我想实现相机应用程序的 2 倍变焦功能 我该怎么做呢 基本上 我希望我的预览层将视频源更改为与您在点击 1x 图标将
  • 有 Objective-C Web 框架吗?

    有 Objective C Web 框架吗 我发现的唯一框架是 frothkit 我主要寻找一种在 Objective C 中编写 RESTful json Web 服务的方法 GNUStepWeb http wiki gnustep or
  • 在 iOS 上保存(私人)应用程序设置?

    我知道NSUserDefaults用于保存 恢复user优先 什么是等效类应用 例如 应用程序可能有一个 上次运行 字段 或者它可能有一个用于在应用程序级别使用的设备的唯一标识的字段 我的目的是将应用程序的设置 而不是用户的设置 保留在设置
  • 无法识别的选择器发送到类

    我已经看到 这是一个常见问题 但我自己找不到任何解决方案 这是代码 class ButtonViewController UIViewController override func viewDidLoad super viewDidLoa
  • UICollectionViewFlowLayout IOS的​​minimumLineSpacing属性

    对于UICollectionViewFlowLayout的属性minimumLineSpacing 苹果的文档说 对于垂直滚动网格 该值表示最小值 连续行之间的间距 对于水平滚动的网格 该值表示连续列之间的最小间距 我测试它和代码的一部分是

随机推荐

  • 型号不同的计算机内存条可以通用么,笔记本内存条和台式机通用吗

    电脑分为笔记本和台式机 这两者里面都有一个很重要的部件就是内存条 虽然作用都是相同的 但两者却是不一样的 那么笔记本内存条和台式机通用吗 答案是不可以 下面小编会给大家详细介绍不能通用的原因 以及笔记本内存条怎么装 看型号等等问题 笔记本内
  • 【Chisel入门——数据类型与操作符号】

    文章目录 前言 Chisel开发环境部署 安装步骤 环境测试 实验环境问题说明 数据类型 UInt SInt Bool Vec T Bundle 操作符 总结 前言 前面的部分简单介绍了Chisel 新型敏捷硬件开发语言 也简单说明了开发环
  • 黑马并发编程JUC(信号量、线程安全类)总结

    黑马并发编程JUC总结 9 JUC Semaphore 定义 原理 acquire release CountDownLatch 为什么需要用到CountDownLatch 定义 为什么加载的时候需要使用到countDownLock 商品问
  • EsayExcle的简单使用

  • Linux应用编程

    孤儿进程 在Linux Unix环境中 我们是通过fork函数来创建子进程的 创建完毕之后 父子进程独立运行 父进程无法预知子进程什么时候结束 通常情况下 子进程退出后 父进程会使用wait或waitpid函数进行回收子进程的资源 并获得子
  • nginx-1.13.x源码安装

    Nginx 安装配置 依赖库 zlib 下载 http download chinaunix net download php id 24013 ResourceID 12241 pcre apt get install libpcre d
  • 地理坐标xy表示什么_地理坐标怎么写 书写格式及方法

    地理坐标怎么写 书写格式及方法 地理坐标是用纬度 经度表示地面点位置的球面坐标 地理坐标系以地 轴为极轴 所有通过地球南北极的平面均称为子午面 地理坐标 就是用经 纬度表示地面点位的球面坐标 1 地理坐标的概念子午面与地球椭球面的交线 称为
  • 代码解析工具汇总

    代码解析工具 一 针对多种语言 ANTLR SonarQube tree sitter 二 针对C语言 pycparser Joern 三 针对Java Javalang JavaParser Eclipse AstParser 四 针对p
  • java:方法重载和方法重写的区别

    方法重载 代码示例 public void set System out println 好好学习 public void set String name System out println 好好学习 方法重写 在不同的类中 在有继承关系
  • 服务器部署JavaWeb的war包(完整版)

    本文章内容操作环境采用的技术是docker部署war 提前下载好Xshell7 终端 如果你买的服务器有终端窗口 那么用你的服务器终端窗口也行 和Xftp7 传输文件 并下载navicat15 版本过低会因为1045 连不上服务器 一 导出
  • 网络基础:协议层次

    目录 一 理论 1 OSI参考模型 2 TCP IP模型 3 OSI模型对应协议 4 TCP IP模型对应协议 5 OSI模型传输数据过程 二 实验 1 TCP IP模型封装 一 理论 一个协议层能够用软件 硬件或者两者的结合来实现 各个层
  • 谷歌浏览器插件Automa_2.点击和输入文字

    操作 普通玩家对于组件的操作无非就输入文字 点击控件跳转页面 但高端玩家会为这些操作加上各种限制条件以让其适应各种网页 而这些内容将在进阶篇介绍 点击 1 找到你要点击的位置 2 定位它 这里有讲如何定位 3 复制那个位置 粘贴到元素选择器
  • Pytorch学习笔记(1)第四章 神经网络工具箱nn

    今天学习内容 https github com chenyuntc pytorch book blob master chapter4 E7 A5 9E E7 BB 8F E7 BD 91 E7 BB 9C E5 B7 A5 E5 85 B
  • 账号和权限管理——设置目录和文件的归属(五)

    设置目录和文件的归属 1 chown 命令 需要设置文件或者目录的归属时 主要通过 chown 命令进行 可以只设置属主或属组 也可以同时设置属主 属组 使用 chown 命令的基本格式如下 chown 属主 属组 文件或目录 同时设置属主
  • django入门:Admin管理系统及表单(干货)

    点击上方蓝字关注公众号 码个蛋第310次推文 作者 Kuky xs 博客 https www jianshu com p 8cdf099e974f 前言 django入门 环境及项目搭建 django入门 数据模型 django入门 视图及
  • Anaconda安装虚拟环境下的Jupyter Notebook没有快捷方式怎么办

    Anaconda安装虚拟环境下的Jupyter Notebook没有快捷方式怎么办 今天为了安装tensorflow 在anaconda环境下创建了一个名称为tensorflow虚拟环境 一波操作装完了tensorflow之后 为了在jup
  • 食品行业仓储条码管理系统解决方案

    食品行业总是保持一贯的稳健增势 而且整体行业在产品结构 市场竞争力 运营成本等方面仍有相当的潜力可以发掘 但食品安全问题 消费者口味的不断变化 多变的渠道模式和供应链效率问题 这些都为食品饮料行业建立了一个动荡的充满挑战和机遇的商业环境 而
  • Oracle 数据库升级

    转载来源 Oracle 数据库升级 https mp weixin qq com s LIDIsmeZRRfZmOVtOkeznQ 一 环境准备 本次测试尽量按照生产环境升级进行模拟 故而使用2台主机进行测试 注意 源库为生产环境 linu
  • 【Java编程】JavaSE基础总结(六):多线程

    JavaSE基础总结 六 进程是程序执行的实体 每一个进程都是一个应用程序 比如我们运行QQ 浏览器 LOL 网易云音乐等软件 都有自己的内存空间 CPU 一个核心同时只能处理一件事情 当出现多个进程需要同时运行时 CPU一般通过 时间片轮
  • [精通Objective-C]块(block)

    精通Objective C 块 block 参考书籍 精通Objective C 美 Keith Lee 目录 精通Objective C块block 目录 块的语法 块的词汇范围 块的内存管理 块的使用 使用块为数组排序 使用块的并行编程