Objective-C 学习笔记 | Block 对象

Objective-C 学习笔记 | Block 对象

  • Objective-C 学习笔记 | Block 对象
    • 编写并使用 Block 对象
    • Block 对象的返回值
    • 匿名 Block 对象
    • 外部变量
    • 在 Block 对象中使用 self
    • 在 Block 对象中无意使用 self
    • 修改外部变量

Objective-C 学习笔记 | Block 对象

Block 对象类似于匿名函数,没有函数名,有返回类型和实参类型,用一个^标识。

请添加图片描述

编写并使用 Block 对象

enumerateObjectsUsingBlock: 方法要求传入的 Block 对象的三个实参类型是固定的。第一个实参是对象指针,指向当前(枚举)的对象。该指针的类型是 id,所以无论数组包含的是什么类型的对象,都可以将地址赋给该指针。第二个实参的类型是 NSUInteger,其值是 当前对象在数组中的索引。第三个实参是指向 BOOL 变量的指针,默认为 NO,如果设为 YES,那么数组对象会在执行完当前的 Block 对象后终止枚举过程。

#import <Foundation/Foundation.h>
// 使用 typedef 定义 Block 对象的类型
typedef void (^ArrayEnumerationBlock)(id, NSUInteger, BOOL *);int main(int argc, const char * argv[]) {@autoreleasepool {NSArray *originalStrings = @[@"Sauerkraut", @"Raygun", @"Big Nerd Ranch", @"Mississippi"];NSLog(@"original strings: %@", originalStrings);NSMutableArray *devowelizedStrings = [NSMutableArray array];NSArray *vowels = @[@"a", @"e", @"i", @"o", @"u"];// 声明 Block 变量// void (^devowelizer)(id, NSUInteger, BOOL *);ArrayEnumerationBlock devowelizer;// 将 Block 对象赋给变量devowelizer = ^(id string, NSUInteger i, BOOL *stop){/**NSRange yRange = [string rangeOfString:@"y" options:NSCaseInsensitiveSearch];if (yRange.location != NSNotFound){*stop = YES; // 执行完当前的 Block 对象后终止枚举过程return; // 结束当前正在执行的 Block 对象}*/NSMutableString *newString = [NSMutableString stringWithString:string];// 枚举数组中的字符串,将所有出现的元音字符替换成空字符串for (NSString *vowel in vowels){NSRange fullRange = NSMakeRange(0, [newString length]);[newString replaceOccurrencesOfString:vowel withString:@"" options:NSCaseInsensitiveSearch range:fullRange];}[devowelizedStrings addObject:newString];}; // Block 变量赋值结束[originalStrings enumerateObjectsUsingBlock:devowelizer];NSLog(@"new strings: %@", devowelizedStrings);}return 0;
}

本程序编写的 Block 对象会复制 originalStrings 数组的字符串,并移除其中所有的元音字母,将修改后的字符串保存到 devowelizedStrings 数组。

Block 对象的返回值

可以像调用函数一样调用 Block 对象,获得返回值:

// 声明 divBlock 变量
double (^divBlock)(double, double);
// 将 Block 对象赋给变量
divBlock = ^(double dividend, double divisor)
{return dividend / divisor;
}
double res = divBlock(3.0, 1.5);

匿名 Block 对象

匿名的 Block 对象是可以传递给方法的 Block 对象的,而不需要先赋值给变量。

外部变量

Block 对象通常会使用外部变量(在其代码外部创建的变量)。当执行 Block 对象时,为了确保其下的外部变量一直存在,相应的 Block 对象会捕获这些变量。

对基本类型的变量,捕获意味着程序会拷贝变量的值,并用 Block 对象内的局部变量保存;对指针类型的变量,Block 对象会使用强引用。这意味着直到 Block 对象释放前,其使用的外部对象都不会被释放,这也是 Block 对象和函数的区别。

在 Block 对象中使用 self

如果需要写一个使用 self 的 Block 对象,那么需要考虑强引用循环的问题。为了解决这个问题,可以在 Block 对象外声明一个 __weak 指针,将这个指针指向 Block 对象使用的 self,最后在 Block 对象里使用弱指针。然而,由于是弱引用,所以 self 指向的对象在 Block 执行时可能被释放,导致出错。为了避免这种情况,可以在 Block 对象中创建一个对 self 的局部强引用,其生命周期和 Block 对象相同,强引用循环也只会在 Block 对象执行时出现:

__weak BNREmployee *weakSelf = self; // 弱引用
myBlock = ^{BNREmployee *innerSelf = weakSelf; // 局部强引用NSLog(@"Employee: %@", innerSelf);
};

在 Block 对象中无意使用 self

如果直接在 Block 对象中使用实例变量,那么block 会捕获 self,而不会捕获实例变量。

以下代码直接存取一个实例变量:

_weak BNREmployee *weakSelf = self;
myBlock = ^{BNREmployee*innerSelf=weakSelf;// 局部强引用NSLog (@"Employee: %@", innerSelf);NSLog (@"Employee ID: %d", _employeeID);
};

编译器在遇到 _employeeID 时,会将其看成 self->_employeeID,self 就被 Block 对象无意地捕获了,这样又造成了强引用循环。

解决方法:不要直接存取实例变量,使用存取方法!

_weak BNREmployee *weakSelf = self;
myBlock = ^{BNREmployee*innerSelf=weakSelf;// 局部强引用NSLog (@"Employee: %@", innerSelf);NSLog (@"Employee ID: %d", innerSelf.employeeID);
};

修改外部变量

在 Block 对象中,被捕获的变量不可被修改。如果需要在 Block 对象内修改某个外部变量,则可以在声明该外部变量时加上 __block 关键字。

例如,下面的代码可以在 Block 对象内将外部变量 counter 值加 1:

__block int counter = 0;
void (^counterBlock)()= ^{ counter++; };
counterBlock(); // counter = 1
counterBlock(); // counter = 2

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/851444.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【代码随想录训练营】【Day 49】【动态规划-8】| Leetcode 139

【代码随想录训练营】【Day 49】【动态规划-8】| Leetcode 139 需强化知识点 多重背包&#xff1a;将其展开为01背包 题目 139. 单词拆分 注意 要保证 单词构成的有序性&#xff0c;先遍历背包&#xff0c;再遍历物品回溯法 class Solution:def wordBreak(self, s: str, …

面对层出不穷的大模型产品,该怎么选呢

层出不穷的大模型产品&#xff0c;你怎么选&#xff1f; 随着近日腾讯元宝APP的正式上线&#xff0c;国内大模型产品又添一员。关于接连出现的“全能“大模型AIGC产品&#xff0c;你都用过哪些呢&#xff1f;不妨来分享一下你的使用体验吧&#xff01;在这些大模型产品中&…

xLua(一) 环境安装笔记

为了方便查阅记录一下xLua的安装地址及方法 1.登录地址下载: https://github.com/Tencent/xLua 2.解压文件 将文件中的这些内容拷贝到项目中的Asset文件夹中 注意 : 工程项目路径不得含有中文 3.将Tools复制到Asset同级目录下 4.导入后会发现有Bug,需要导入工程 5.还有另…

Java:九九乘法表,打印三角形

文章目录 九九乘法表打印三角形改进:控制行数的三角形有空格的三角形 九九乘法表 package com.zhang; /* 打印九九乘法表*/ public class Test8 {public static void main(String[] args) {//i是竖着的 j是横着的for (int i 1; i < 9; i) {for(int j 1; j < 9; j) {i…

IP协议(二)

TOC 一: 网段划分 同一个局域网的主机,要按一定的规则分配IP地址 把一个IP地址分为两部分: 前半部分 ,网络号 >用来表示局域网后半部分,主机号 > 用来区分同一个局域网中的不同主机 同一个局域网内部&#xff0c;主机之间的IP &#xff0c; 网络号相同&#xff0c;主…

JS笔记(自用)

1、js输出&#xff1a;console.log("hellowworld"); 2、变量定义&#xff1a;var&#xff0c;变量名区分大小写 3、数据类型&#xff1a; 基本数据类型&#xff1a;number&#xff08;整数浮点数&#xff0c;NaN非数&#xff0c;正负无穷大&#xff09;。boolean。…

Python 虚拟环境 + 嵌入式 + 编译pyd 部署方案

Python 虚拟环境 嵌入式 编译pyd 部署方案 开发阶段 - 直接发源码版本1. 在虚拟环境下开发 Python 项目 部署阶段1. 创建项目文件夹2. 准备嵌入器 Python 解释器3. 处理第三方库4. 修改 ._pth 文件添加 Python 运行环境5. 添加启动 bat 脚本 目录结构开发阶段 - 编译 pyd 再发…

vue-router的导入和使用

关于如何在 Vue.js 中导入和使用 vue-router 的基本例子。 首先&#xff0c;确保你已经安装了 vue-router。你可以通过 npm 或 yarn 来安装&#xff1a; npm install vue-router # 或者 yarn add vue-router 然后&#xff0c;在你的 Vue 项目中&#xff0c;你可以按照以下…

FuTalk设计周刊-Vol.039

&#x1f525;AI漫谈 热点捕手 1、AI视频生成工具大PK | Runway Gen-2、Pika、Moonvalley和W.A.L.T的文字生视频对比评测 AI届的学术大牛李飞飞最近推出了用于生成逼真视频的扩散模型W.A.L.T。效果很不错&#xff0c;不过目前还未开放公网的访问。于是我萌生了一个想法&#…

气体流量的换算

测量气体流量时&#xff0c;往往需要进行温压补偿。我们可以选择Nm:/h和m3/h作为测量单位&#xff0c;二者之间如何换算呢?在标准状态下&#xff0c;即温度为0℃℃(273.15K)和压力为1个标准大气压(101.325kPa)时&#xff0c;气体的体积被称为Nm3(标方)&#xff0c;N代表标准条…

音视频主要概念

文章目录 常用的一些概念主要概念1主要概念2I帧P帧B帧 常用视频压缩算法 小结 常用的一些概念 主要概念1 视频码率&#xff1a;kb/s&#xff0c;是指视频文件在单位时间内使用的数据流量&#xff0c;也叫码流率。码率越大&#xff0c;说明单位时间内取样率越大&#xff0c;数…

rust asyn和await pin unpin加精!!!

15-探讨为什么Pin在Rust异步编程中如此重要 | Databend_哔哩哔哩_bilibili 能不能Pin住&#xff0c;取决于T是否实现了Unpin&#xff0c;如果实现了Unpin&#xff0c;那么Pin不住 Pin不能pin住u32等基础变量 编译器为async和await生成结构体实现了!Unpin 结构体中使用引用要…

智能合约中Gas限制和DoS攻击漏洞

Gas限制和DoS攻击 Gas限制和DoS&#xff08;Denial of Service&#xff0c;拒绝服务&#xff09;攻击是在区块链和智能合约环境下常见的安全威胁&#xff0c;尤其是对于像以太坊这样的平台&#xff0c;其中Gas是一种用于衡量执行智能合约成本的单位。Gas机制设计的初衷是为了防…

62- 读写文件详解

一 读写文本文件(QFile 类) Qt 开发中的 QFile 类支持对文件进行读取、写入、删除、复制 重命名等相关操作,它既可以操作文本文件,也可以操作二进制文件。 #include <QCoreApplication> #include <QFile> #include <QDebug> int main(int argc, char *argv…

Java 18新特性全览:探索Java世界的最新进化!

随着技术的不断演进&#xff0c;Java作为历史悠久的编程语言&#xff0c;始终保持着其时代的前沿性。Java 18的发布&#xff0c;又一次展示了这门语言的强大生命力和不断创新的能力。在本文中&#xff0c;我们将深入探讨Java 18带来的那些令人兴奋的新特性&#xff0c;助你领略…

HTML+CSS 交互式开关按钮

效果演示 实现了一个交互式开关按钮的效果,包括一个标签和两个选项(Yes和No),当用户点击其中一个选项时,按钮会发生动画效果,同时选中的选项会被高亮显示。整个按钮的样式采用了渐变背景色、圆角边框、阴影等元素,使得按钮看起来更加美观。 Code HTML <!DOCTYPE ht…

下拉框数据被遮挡 且 后续数据无法下拉的 解决方法

目录 前言1. 问题所示2. 原理分析3. 解决方法3.1 添加空白版2.2 调整z-index2.3 父容器的溢出属性2.4 调整样式属性4. 效果图前言 小程序使用的是Uniapp,原理都差不多,索性标题就不标注Uniapp(小程序) 对于该问题调试了一个晚上,最终解决,对此记录下来 1. 问题所示 执…

JVM常用概念之线程本地分配缓冲区(ThreadLocal Allocation Buffer,TLAB)

当实例化一个Java类时&#xff0c;运行时环境必须为相关实例分配存储空间&#xff0c;在JRE中此存储空间分配操作是由内存管理器实现的&#xff08;其实是JVM的垃圾回收器&#xff09;&#xff0c;由于内存管理器通常使用与运行时目标语言不同的语言编写&#xff08;例如&#…

图片转pdf在线网站,图片转pdf在线网址,工具软件

在现代办公和学习环境中&#xff0c;图片转PDF的操作已变得日益重要。无论是为了存档、分享还是打印&#xff0c;将图片转换为PDF格式都能带来诸多便利。本文将详细介绍几种常用的图片转PDF方法。 打开 “轻云pdf处理官网” &#xff0c;上传图片。 图片上传完成后&#xff0…

AI学习指南机器学习篇-决策树在python中的实现

AI学习指南机器学习篇-决策树在Python中的实现 机器学习是人工智能领域中的重要分支&#xff0c;它涉及许多复杂的概念和技术。在机器学习的算法中&#xff0c;决策树是一种常用的监督学习方法&#xff0c;它可以帮助我们预测未来事件的发生或者分类数据。本篇文章将介绍如何使…