【iOS】——属性关键字

属性关键字的类型

在iOS中属性关键字分为四种类型:

  • 可访问性: readonly ,readwrite
  • 原子性 : atomic ,nonatomic
  • 内存管理 : retain/strong/copy, assign/unsafe_unretained,weak
  • 方法命名:setter,getter

1.可访问性

readonly:表示只读属性,只会生成getter方法 ,不会生成setter方法,无法通过 setter 方法进行修改。
readwrite:与 readonly 相对,表示读写属性,会生成getter和setter方法,可以通过 setter 方法修改属性值。

2.原子性

atomic:提供了一定程度的线程安全性,确保对属性的读取和写入操作是原子的,即在同一时间只有一个线程可以访问属性。这是通过给属性的访问器方法(getter 和 setter)加锁来实现的。
nonatomic:属性的访问是非原子的,不提供线程安全保护。在多线程环境下,多个线程同时访问和修改属性可能会导致数据不一致的情况。nonatomic 通常具有更高的性能,因为不需要额外的加锁和同步操作。

atomic只针对属性的 getter/setter 方法进行加锁,所以安全只是针对getter/setter方法来说,并不是整个线程安全,因为一个属性并不只有 setter/getter 方法,例:(如果一个线程正在getter 或者 setter时,有另外一个线程同时对该属性进行release操作,如果release先完成,会造成crash)

3.内存管理:

weak

用于表示对对象的弱引用,不会增加对象的引用计数。当所引用的对象被释放时,弱引用会自动置为 nil。

在ARC环境下,为避免循环引用,往往会把delegate属性用weak修饰;在MRC下使用assign修饰。当一个对象不再有strong类型的指针指向它的时候,它就会被释放,即使还有weak型指针指向它,那么这些weak型指针也将被清除。

assign

经常用于非指针变量,用于基础数据类型 (例如NSInteger)和C数据类型(int, float, double, char, 等),另外还有id类型。用于对基本数据类型进行复制操作,不更改引用计数。

也可以用来修饰对象,但是,被assign修饰的对象在释放后,指针的地址还是存在的,也就是说指针并没有被置为nil,成为野指针

之所以可以修饰基本数据类型,因为基本数据类型一般分配在栈上,栈的内存会由系统自动处理,不会造成野指针。MRC下的delegate往往assgin,此操作是为了deletage和self等自身产生循环引用。

weak 和 assign 的区别:

修饰的对象:weak修饰oc对象类型的数据,assign用来修饰是非指针变量。

引用计数:weak 和 assign 都不会增加引用计数。

释放:weak 修饰的对象释放后,指针地址自动设置为 nil,assign修饰的对象释放后指针地址依然存在,成为野指针。

修饰delegate 在MRC使用assign,在ARC使用weak。

strong

修饰一些OC对象类型的数据如:(NSNumber,NSString,NSArray、NSDate、NSDictionary、模型类等),strong是强引用,在ARC下等于retain,这一点区别于weak。

strong是我们通常所说的指针拷贝(浅拷贝),内存地址保持不变,只是产生了一个新的指针,新指针和引用对象的指针指向同一个内存地址,没有生成新的对象,多了一个指向该对象的指针。

由于使用的是一个内存地址,当该内存地址存储的内容发生变更的时候,会导致属性也跟着变更

copy

用于修饰OC对象类型的数据,在调用setter方法给成员变量赋值时,会将被赋值的对象生成一个副本,然后将该副本赋值给成员变量。

在MRC,用来修饰block,因为block需要从栈区copy到堆区,在ARC,系统自动给我们做了这个操作,所一现在使用strong或者copy来修饰block都是可以的。

copy和strong都是属于强引用,都会让属性的引用计数加一,但是copy和strong不同点在于,它所修饰的属性当引用一个属性值时,是内存拷贝(深拷贝),就是在引用是,会生成一个新的内存地址和指针地址,和引用对象完全没有相同点,因此它不会因为引用属性的变更而改变。

copy与strong的区别(深拷贝 浅拷贝):

copy:内存拷贝-深拷贝,内存地址不同,指针地址也不同。
storng: 指针拷贝-浅拷贝,内存地址不变,指针地址不同

声明两个copy属性,两个strong属性,分别为可变和不可变类型:

@property(nonatomic,strong)NSString * Strstrong;
@property(nonatomic,copy)NSString * Strcopy;
@property(nonatomic,copy)NSMutableString * MutableStrcopy;
@property(nonatomic,strong)NSMutableString * MutableStrstrong;`

用不可变对象对属性进行赋值:

```
NSString * OriginalStr = @"我已经开始测试了";
//对 不可变对象赋值 无论是 strong 还是 copy 都是原地址不变,生成一个新指针指向对象(浅拷贝)
self.Strcopy = OriginalStr;
self.Strstrong = OriginalStr;
self.MutableStrcopy = OriginalStr;
self.MutableStrstrong = OriginalStr;
NSLog(@"rangle=>%@\n normal:copy=>%@=====strong=>%@\nMutable:copy=>%@=====strong=>%@",OriginalStr,_Strcopy,_Strstrong,_MutableStrcopy,_MutableStrstrong);
NSLog(@"rangle=>%p\n normal:copy=>%p=====strong=>%p\nMutable:copy=>%p=====strong=>%p",OriginalStr,_Strcopy,_Strstrong,_MutableStrcopy,_MutableStrstrong);
NSLog(@"rangle=>%p\n normal:copy=>%p=====strong=>%p\nMutable:copy=>%p=====strong=>%p",&OriginalStr,&_Strcopy,&_Strstrong,&_MutableStrcopy,&_MutableStrstrong);
```

在这里插入图片描述

strong修饰的对象和copy修饰的对象都是在引用一个对象的时候,内存地址是一样的,只有指针地址不同。

所以对于不可变对象进行赋值,使用strong和copy关键字都是进行的浅拷贝,即对象内存地址不变,指针地址改变

用可变对象对属性进行赋值:

```
NSMutableString * OriginalMutableStr = [NSMutableString stringWithFormat:@"我已经开始测试了"];
self.Strcopy = OriginalMutableStr;
self.Strstrong = OriginalMutableStr;
self.MutableStrcopy = OriginalMutableStr;
self.MutableStrstrong = OriginalMutableStr;
```

在这里插入图片描述

strong修饰的属性内存地址依然没有改变,但是copy修饰的属性内存值产生了变化

对可变对象赋值 strong 是原地址不变,引用计数+1(浅拷贝)。 copy是生成一个新的地址和对象,生成一个新指针指向新的内存地址(深拷贝)

此时修改一下OriginalMutableStr的值,看看结果:

```
[OriginalMutableStr appendFormat:@"改变了"];
```

在这里插入图片描述

当改变原来的值后strong修饰的属性的内容也跟着改变了,而copy修饰的属性的内容没有发生改变。

由于OriginalMutableStr是可变类型,是在原有内存地址上进行修改,无论是指针地址和内存地址都没有被改变,只是当前内存地址所存放的数据进行改变。

由于 strong 修饰的属性虽然指针地址不同,但是指针是指向原内存地址的,所以会跟着 OriginalMutableStr 的改变而改变。

copy修饰的类型不仅指针地址不同,而且指向的内存地址也和OriginalMutableStr 不一样,所以不会跟着 OriginalMutableStr 的改变而改变。

使用self.Strcopy 和 _Strcopy 来赋值也是两个不一样的结果,因为后者没有调用 set 方法,而 copy 和 strong 之所以会产生差别就是因为在 set 方法中,copy修饰的属性: 调用了 _Strcopy = [Strcopy copy] 方法。

多种copy模式:copy 和 mutableCopy 对容器对象 进行操作

在对容器对象(NSArray)进行copy操作时,分为多种:

  • copy:仅仅进行了指针拷贝
  • mutableCopy:进行内容拷贝这里的单层指的是完成了NSArray对象的深copy,而未对其容器内对象进行处理使用(NSArray对象的内存地址不同,但是内部元素的内存地址不变)
    [array copy];[array  mutableCopy];
  • 双层深拷贝:这里的双层指的是完成了NSArray对象和NSArray容器内对象的深copy(为什么不是完全,是因为无法处理NSArray中还有一个NSArray这种情况)使用:
    [[NSArray alloc] initWithArray:arr copyItems:YES]
  • 完全深拷贝:完美的解决NSArray嵌套NSArray这种情形,可以使用归档、解档的方式可以使用:

        [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:testArr]];

问题总结

  1. NSMutableArray用copy修饰会出现什么问题?

出现调用可变方法不可控问题,会导致程序崩溃。对于可变对象使用copy关键字会进行深拷贝,返回一个不可变的对象,对不可变的对象调用可变方法就会crash

2.copy关键字影响了对象的可变和不可变属性吗?

  • 可变对象(mutable)copy和mutableCopy都是深拷贝
  • 不可变对象(immutable)的copy是浅拷贝,mutableCopy是深拷贝

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

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

相关文章

W3C XML Schema 活动

关于《W3C XML Schema 活动》的信息,我找到了一些相关资料。XML Schema 是一种基于 XML 的DTD(文档类型定义)替代物,它提供了对应用程序、文档结构、属性和数据类型的更好支持。XML 1.0 版本支持可定义文档结构的DTD,而…

Linux 动静态库

一、动静态库 1、库的理解 库其实是给我们提供方法的实现,如上面的对于printf函数的实现就是在库中实现的,而这个库也就是c标准库,本质也是文件,也有对应的路径 2、区别 静态库是指编译链接时,把库文件的代码全部加入…

前端canvas——赛贝尔曲线

曲线之美,不在于曲线本身,而在于用的人。 所以就有了这期赛贝尔曲线。 新规矩,先上个GIT。 效果图 开局一张图,代码全靠编。 代码 画骨 先想着怎么画一个心形吧,等你想好了,就知道怎么画了。 首先就还…

ES(Elasticsearch)常用的函数有哪些?

【电子书大全】内含上千本顶级编程书籍,是程序员必备的电子书资源包,并且会不断地更新,助你在编程的道路上更上一层楼! 链接: https://pan.baidu.com/s/1yhPJ9LmS_z5TdgIgxs9NvQ?pwdyyds > 提取码: yyds Elasticsearch&#x…

Cyberchef基础概念之-循环语句操作-Jump/Label

在本专栏的前面的文章介绍了fork,merge,subsection,register等多种概念来解决实际场景的问题。本文将介绍的Jump/Label的操作类似于编程语言中的for和while的功能,相信在学会使用jump操作后,将有助于解决更为复杂的数据处理问题。 本文将详细的介绍该操…

Matplotlib : Python 的绘图库

Matplotlib 是一个 Python 的绘图库,广泛用于生成各种静态、动态、交互式的图表。它基于 NumPy,一个用于科学计算的 Python 库。Matplotlib 可以用于生成出版质量级别的图表,并且提供了丰富的定制选项,以适应不同用户的需求。以下…

linux对标画图板的软件

而不是对标photoshop sudo apt-get install kolourpaint

渗透测试 - 攻击思路与手段、工具分享

导语: 我在CSDN活跃已有6年,这是国内最优秀的IT学习平台之一。尽管有人对其持批评态度,我个人认为它拥有独特的优势。 最近我参加了一场网络安全工作的面试,在广州与面试官深入交流了半个多小时。尽管未能通过面试,但这…

每日OJ_力扣+牛客_另类加法_不用加号的加法

目录 力扣面试题 17.01. 不用加号的加法 解析代码 牛客另类加法 解析代码 力扣面试题 17.01. 不用加号的加法 面试题 17.01. 不用加号的加法 设计一个函数把两个数字相加。不得使用 或者其他算术运算符。 示例: 输入: a 1, b 1 输出: 2提示: a, b 均可能…

心跳机制详解

1、什么是心跳机制? 心跳机制出现在TCP长连接中,客户端和服务端之间定时发送一种特殊的数据包通知对方还在线,以确保TCP连接地可靠性,有可能TCP连接由于某些原因(例如网线被拔了,突然断电)导致…

iOS中的KVO(Key-Value Observing)详解

iOS中的KVO(Key-Value Observing)详解 一、KVO概述 KVO(Key-Value Observing),即键值观察/监听,是苹果提供的一套事件通知机制。它允许一个对象(观察者)观察/监听另一个对象&#…

【网络安全】文件上传基础及过滤方式

文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷,导致用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这些文件可以是木马、病毒、恶意脚本或者WebShell等。“文件上传”本身没有问题,有问题的是文件上传后&#xf…

OpenSSL学习笔记及在项目中的使用

OpenSSL官方命令手册:OpenSSL commands - OpenSSL Documentation 参考教程: 操作:OpenSSL的基本使用教程(一)_openssl.exe使用教程-CSDN博客 操作:Linux和Shell回炉复习系列文章总目录 - 骏马金龙 - 博客园 (cnblog…

SAP主生产计划流程

流程概述 生产计划,在系统中体现为计划独立需求该数据元素,是SAP系统组织生产计划/运行MPS主生产计划(是平衡供需的支点)或MRP物料需求计划的源头数据,本流程描述了生产单位在ERP系统中生产计划管理流程。企业的主生产计划员通常以正式销售订单或备货订单为主要依据编制最…

【MR】现代机器人学-时间最优时间缩放

MR章节目录 第2章 配置空间 第3章 刚体运动 第4章 正向运动学 第5章 速度运动学与静力学 第6章 逆向运动学 第7章 闭链运动学 第8章 开链动力学 第9章 轨迹生成 9.1 定义 9.2 点到点轨迹 9.3 多项式通过点轨迹 9.4 时间最优时间缩放 第10章 运动规划 第11章 机器人控制 第12章 …

20 Python常用内置函数——eval()

内置函数 eval() 函数用来计算字符串的值,在有些场合也可以用来实现类型转换的功能。除此之外,eval() 也可以对字节串进行求值,还可以执行内置函数 compile() 编译生成的代码对象。 print(eval(b35)) print([eval(8), type(eval(8))]) # 把…

Keras入门:一维线性回归问题

目录 一、一维变量线性回归 1. 数据生成 2. 建立训练模型 3. 作图 4. 完整代码 一、一维变量线性回归 1. 数据生成 import keras import numpy as np import matplotlib.pyplot as plt #matplotlib inline xnp.linspace(0, 100, 30) #0~100之间,生成30个数 y…

.NET Core 中的字符串压缩方法

字符串压缩的概念 字符串压缩通常指的是通过算法减少字符串表示所需的数据量,同时保持字符串的原始信息或能够无损地恢复原始字符串。这种压缩可以是针对文本数据的特定算法,也可以是更通用的数据压缩算法。 .NET Core 中的字符串压缩方法 使用数据压…

linux 回到根目录

linux下如何回到根目录? cd / 以根目录开头 (切换到系统根目录) cd ~ 回到自己的home目录(切换到用户主目录) /home/用户名 cd .. 返回上级目录 cd - 回看功能 pwd 查看当前目录

构建现代数据湖

现代数据湖是一半数据仓库和一半数据湖,对所有事情都使用对象存储。使用对象存储来构建数据仓库是通过 Open Table Formats OTF) 实现的,例如 Apache Iceberg、Apache Hudi 和 Delta Lake,这些规范一旦实现,就可以无缝…