当前位置: 首页 > news >正文

OC-Block

关于OC中的block作为属性时,为什么要要用copy修饰

@property (nonatomic, copy) void (^completionBlock)(void);

很多文章包括AI都会给出类似结论

  • Block 默认分配在栈上,如果没有 copy,当方法退出后,Block 会被销毁。
  • 使用 copy 修饰符确保 Block 存储在堆上,避免栈上 Block 在方法返回后被销毁,确保 Block 在属性中能够正常存活和使用。
  • copy 是为了让 Block 在对象的生命周期内持久化,尤其是当 Block 需要在方法执行后继续使用时。

然而,随着技术的迭代优化,这些知识恐怕已经过时了,我们来看下面的demo

@interface ViewController ()@property (nonatomic, copy) void(^demoBolck)(void);@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.void (^tmpBlock)(void) = ^{NSLog(@"bolck called");};NSLog(@"tmpBlock %@", tmpBlock);_demoBolck = tmpBlock;NSLog(@"demoBolck %@", tmpBlock);_demoBolck();
}@end

 输出结果是这样的

tmpBlock <__NSGlobalBlock__: 0x1067cf490>

demoBolck <__NSGlobalBlock__: 0x1067cf490>

bolck called

我们看到,未引用任何外部变量的block初始化之后就是 “__NSGlobalBlock__”,在全局内存中存储,然后被当前页面的demoBlock属性引用,虽然设置了copy,但是并没有复制(内存没变)。因为他已经在全局内存了,生命周期和APP是一致的,后面随时可以调用,没有复制的必要了。我们甚至使用weak修饰这个属性也可以在后续代码中调用block:

@property (nonatomic, weak) void(^demoBolck)(void);

说到这里我们稍微展开一下,根据GPT的回答,block的存储方式有三种,原文大致如下:

  • 栈内存:用于存储局部变量和不捕获外部变量的 block。栈上的 block 会在离开作用域时自动销毁,名字:__NSStackBlock__。
  • 堆内存:用于存储捕获外部变量的 block,以及所有动态分配的对象,名字:__NSMallocBlock__。
  • 全局内存:用于存储常量和全局变量,且包括不捕获外部变量的 block,名字__NSGlobalBlock__。

有没有发现,关于栈内存和全局内存的说明是有重复的,理解起来好像是“不捕获外部变量的 block”既可以在全局内存存储也可以在栈内存存储。这里触发了他的知识盲区,反复询问也没说明白。所以我们需要继续自己做实验来验证。

既然说如果block引用了“外部变量”就会自动到堆内存,我们试一下

@interface ViewController ()@property (nonatomic, copy) void(^demoBolck)(void);@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view.NSString *pageName = @"ViewController";void (^tmpBlock)(void) = ^{NSLog(@"bolck called in %@", pageName);};NSLog(@"tmpBlock %@", tmpBlock);_demoBolck = tmpBlock;NSLog(@"demoBolck %@", tmpBlock);_demoBolck();
}@end

打印结果

tmpBlock <__NSMallocBlock__: 0x7b0c000fc3c0>

demoBolck <__NSMallocBlock__: 0x7b0c000fc3c0>

bolck called in ViewController

的确,引用了外部变量之后,block直接被存储到了堆内存(名字是__NSMallocBlock__),这种情况下属性的copy依然没什么卵用,copy、strong都没有什么变化,且后续调用都正常。

还做了其他实验,简单说一下

  • 如果block仅引用了一个全局变量,block还会存在全局内存中
  • 如果block引用了当前类的一个属性,block会存在堆内存中,和局部变量一致

众多实验中,唯独没有找到block存储在栈内存中的情况,本人孤陋寡闻,望熟悉的大哥不吝赐教。

总结

1、早期的程序设计中,如果仅仅是局部作用的block,大概率是存在栈内存中的,用完就被释放掉了。然后如果被传递给了某个类来引用,需要开发者自己通过设置属性为“copy”类型实现复制到堆内存中,以便启用引用计数来管理其生命周期,所以大家都用copy来修饰block属性。

2、现阶段的环境下(我用的Xcode Version 16.2 (16C5032a),iOS18.1,模拟器),苹果做了优化。直接根据block是否引用变量,以及所引用的变量的生命周期来控制block的存储位置,和我们给的属性修饰(copy、strong)没关系了。

为什么这么做呢?我们使用block的时候,大多数情况不会在当前作用域创建并直接调用,也就是大概率是将来的某个时候回调,那他就不是临时的,就会和我们的一些变量关联起来,需要一起管理其生命周期。如果还是老逻辑,那大概率都会从栈中复制到堆,折腾一次,优化概率远效率浪费的概率。所以这种设计逐渐被抛弃了。我没找到官方文档,仅个人猜测。

接下来

1、低版本的iOS系统我们大概率都要支持几个的,所以当下并不一定所有的版本都启用了这个机制,具体从什么时候变的我不知道,没找到机器。所以还是推荐大家继续使用copy来修饰block属性

2、 如果大家一起探讨这个问题,就要加上版本这个变量,新版本什么样,老版本什么样

相关文章:

OC-Block

关于OC中的block作为属性时&#xff0c;为什么要要用copy修饰 property (nonatomic, copy) void (^completionBlock)(void);很多文章包括AI都会给出类似结论 Block 默认分配在栈上&#xff0c;如果没有 copy&#xff0c;当方法退出后&#xff0c;Block 会被销毁。使用 copy 修…...

关于知识蒸馏的概念原理以及常见方法

1. 概念与原理 知识蒸馏的基本定义 知识蒸馏(Knowledge Distillation) 是一种将模型压缩与迁移学习结合的技术:它利用预先训练好的大模型(通常参数量大、精度高、计算开销大)指导一个更轻量(参数量小、推理速度快)的学生模型进行训练,从而在保持模型精度的同时显著减少…...

C++轻量级桌面GUI库FLTK

C轻量级桌面GUI库FLTK Screenshots - Fast Light Toolkit (FLTK) 这里写个备忘录,可以参考一下....

C++20导出模块及使用

1.模块声明 .ixx文件为导入模块文件 math_operations.ixx export module math_operations;//模块导出 //导出命名空间 export namespace math_ {//导出命名空间中函数int add(int a, int b);int sub(int a, int b);int mul(int a, int b);int div(int a, int b); } .cppm文件…...

PID 算法简介(C语言)

一、简介: PID是比例、积分、微分三个环节的组合,用来进行反馈控制。每个部分都有对应的系数,也就是Kp、Ki、Kd。PID 算法实现这三个部分的计算,然后综合起来得到控制输出。 二、PID控制器结构体: PID控制器结构体:包含PID参数(Kp, Ki, Kd);存储积分项和上一次误差;…...

Java中的继承及相关概念

在 Java 中&#xff0c;继承是一种允许一个类继承另一个类的特性。通过继承&#xff0c;子类可以获取父类的属性和方法&#xff0c;这有助于减少代码冗余并提高代码的可维护性。以下是关于文件内容的相关分析和知识点总结&#xff1a; 一、继承的核心概念 1.继承的语法 Java …...

语言月赛 202308【小粉兔做麻辣兔头】题解(AC)

》》》点我查看「视频」详解》》》 [语言月赛 202308] 小粉兔做麻辣兔头 题目描述 粉兔喜欢吃麻辣兔头&#xff0c;麻辣兔头的辣度分为若干级&#xff0c;用数字表示&#xff0c;数字越大&#xff0c;兔头越辣。为了庆祝粉兔专题赛 #1 的顺利举行&#xff0c;粉兔要做一些麻…...

云原生后端|实践?

云原生&#xff08;Cloud Native&#xff09;是一种构建和运行应用程序的方法&#xff0c;它充分利用云计算的优势&#xff0c;包括弹性、可扩展性、高可用性和自动化运维。云原生后端开发通常涉及微服务架构、容器化、持续集成/持续部署&#xff08;CI/CD&#xff09;、服务网…...

GrassWebProxy

GrassWebProxy第一版&#xff1a; using System; using System.Collections.Generic; using System.Linq; using System.Net.Sockets; using System.Net; using System.Text; using System.Threading; using System.Threading.Tasks; using System.IO; using Newtonsoft.Json;…...

6.Python函数:函数定义、函数的类型、函数参数、函数返回值、函数嵌套、局部变量、全局变量、递归函数、匿名函数

1. 函数定义 Python函数通过def关键字定义。一个函数通常包括函数名、参数列表和函数体。 def greet(name):return f"Hello, {name}!"2. 函数的类型 Python中的函数主要有以下几种类型&#xff1a; 普通函数&#xff1a;具有明确的输入参数和返回值。递归函数&am…...

青少年编程与数学 02-008 Pyhon语言编程基础 22课题、类的定义和使用

青少年编程与数学 02-008 Pyhon语言编程基础 22课题、类的定义和使用 一、类类的定义和使用示例 二、定义1. 类定义语法2. 属性和方法3. 构造器和初始化4. 实例化5. 类变量和实例变量6. 类方法和静态方法7. 继承8. 多态总结 三、使用1. 创建类的实例2. 访问属性3. 调用方法4. 修…...

CosyVoice /F5-TTS /GPT-SoVITS /Fish-Speech 开源语音克隆与文本转语音(TTS)项目的对比整理

四个主流开源语音克隆与文本转语音&#xff08;TTS&#xff09;项目的对比整理&#xff0c;基于公开资料与实测反馈总结&#xff1a; 项目CosyVoice F5-TTS GPT-SoVITS Fish-Speech 核心技术双向流式语音合成&#xff0c;支持离线与流式一体化建模基于流匹配的ConvNeXt文本表示…...

MySQL基于binlog和gtid主从搭建方案

MySQL基于binlog和gtid主从搭建方案 一.主库配置 1.1 确认 binlog 是否开启 SHOW VARIABLES LIKE %log_bin%; 1.2 创建日志目录并设置权限 mkdir -p /opt/mysql/log_bin chown -R mysql:mysql /usr/local/mysql chmod -R 755 /usr/local/mysql 1.3 修改 my.cnf 配置文件 …...

5 计算机网络

5 计算机网络 5.1 OSI/RM七层模型 5.2 TCP/IP协议簇 5.2.1:常见协议基础 一、 TCP是可靠的&#xff0c;效率低的&#xff1b; 1.HTTP协议端口默认80&#xff0c;HTTPSSL之后成为HTTPS协议默认端口443。 2.对于0~1023一般是默认的公共端口不需要注册&#xff0c;1024以后的则需…...

Vim跳转文件及文件行结束符EOL

跳转文件 gf 从当前窗口打开那个文件的内容&#xff0c;操作方式&#xff1a;让光标停在文件名上&#xff0c;输入gf。 Ctrlo 从打开的文件返回之前的窗口 Ctrlwf 可以在分割的窗口打开跳转的文件&#xff0c;不过在我的实验不是次次都成功。 统一行尾格式 文本文件里存放的…...

智能理解 PPT 内容,快速生成讲解视频

当我们想根据一版 PPT 制作出相对应的解锁视频时&#xff0c;从撰写解锁词&#xff0c;录制音频到剪辑视频&#xff0c;每一个环节都需要投入大量的时间和精力&#xff0c;本方案将依托于阿里云函数计算 FC 和百炼模型服务&#xff0c;实现从 PPT 到视频的全自动转换&#xff0…...

【鸿蒙开发】第二十四章 AI - Core Speech Kit(基础语音服务)

目录 1 简介 1.1 场景介绍 1.2 约束与限制 2 文本转语音 2.1 场景介绍 2.2 约束与限制 2.3 开发步骤 2.4 设置播报策略 2.4.1 设置单词播报方式 2.4.2 设置数字播报策略 2.4.3 插入静音停顿 2.4.4 指定汉字发音 2.5 开发实例 3 语音识别 3.1 场景介绍 3.2 约束…...

Java/Kotlin双语革命性ORM框架Jimmer(一)——介绍与简单使用

概览 Jimmer是一个Java/Kotlin双语框架 包含一个革命性的ORM 以此ORM为基础打造了一套综合性方案解决方案&#xff0c;包括 DTO语言 更全面更强大的缓存机制&#xff0c;以及高度自动化的缓存一致性 更强大客户端文档和代码生成能力&#xff0c;包括Jimmer独创的远程异常 …...

番外02:前端八股文面试题-CSS篇

一&#xff1a;CSS基础 1&#xff1a;CSS选择器及其优先级 2&#xff1a;display的属性值及其作用 属性值作用none元素不显示&#xff0c;并且会从文档流中移除block块类型&#xff0c;默认元素为父元素宽度&#xff0c;可设置宽高&#xff0c;换行显示inline行内元素类型&a…...

Redis Copilot:基于Redis为AI打造的副驾工具

我们最近发布了Redis Copilot&#xff0c;以帮助开发者更快地使用Redis构建应用。我们的使命是使应用程序快速运行&#xff0c;并简化构建过程。为此&#xff0c;Redis Copilot作为您的AI助手&#xff0c;能够让您更迅速地完成与Redis相关的任务。您今天就可以在Redis Insight中…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

MFC内存泄露

1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...

Opencv中的addweighted函数

一.addweighted函数作用 addweighted&#xff08;&#xff09;是OpenCV库中用于图像处理的函数&#xff0c;主要功能是将两个输入图像&#xff08;尺寸和类型相同&#xff09;按照指定的权重进行加权叠加&#xff08;图像融合&#xff09;&#xff0c;并添加一个标量值&#x…...

测试markdown--肇兴

day1&#xff1a; 1、去程&#xff1a;7:04 --11:32高铁 高铁右转上售票大厅2楼&#xff0c;穿过候车厅下一楼&#xff0c;上大巴车 &#xffe5;10/人 **2、到达&#xff1a;**12点多到达寨子&#xff0c;买门票&#xff0c;美团/抖音&#xff1a;&#xffe5;78人 3、中饭&a…...

c++ 面试题(1)-----深度优先搜索(DFS)实现

操作系统&#xff1a;ubuntu22.04 IDE:Visual Studio Code 编程语言&#xff1a;C11 题目描述 地上有一个 m 行 n 列的方格&#xff0c;从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子&#xff0c;但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

vue3 字体颜色设置的多种方式

在Vue 3中设置字体颜色可以通过多种方式实现&#xff0c;这取决于你是想在组件内部直接设置&#xff0c;还是在CSS/SCSS/LESS等样式文件中定义。以下是几种常见的方法&#xff1a; 1. 内联样式 你可以直接在模板中使用style绑定来设置字体颜色。 <template><div :s…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

九天毕昇深度学习平台 | 如何安装库?

pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子&#xff1a; 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

用机器学习破解新能源领域的“弃风”难题

音乐发烧友深有体会&#xff0c;玩音乐的本质就是玩电网。火电声音偏暖&#xff0c;水电偏冷&#xff0c;风电偏空旷。至于太阳能发的电&#xff0c;则略显朦胧和单薄。 不知你是否有感觉&#xff0c;近两年家里的音响声音越来越冷&#xff0c;听起来越来越单薄&#xff1f; —…...