用@property声明的NSString(或NSArray,NSDictionary)经常使用copy关键字,为什么?如果改用strong关键字,可能造成什么问题?

本文详细解释了在iOS开发中使用copy而非strong的原因,特别是在处理可变对象时如何保证对象属性的安全性和不变性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个问题可能大家都知道,但是可能不能够特别系统的讲出原因,今天特地去查了下,觉得写的很不错。这是最近比较火的《招聘一个靠谱的 iOS》答案文章中的一段~


1、因为父类指针可以指向子类对象,使用copy的目的是为了让本对象的属性不受外界影响,使用copy无论给我传入是一个可变对象还是不可对象,我本身持有的就是一个不可变的副本.

2、如果我们使用是strong,那么这个属性就有可能指向一个可变对象,如果这个可变对象在外部被修改了,那么会影响该属性.


copy此特质所表达的所属关系与strong类似。然而设置方法并不保留新值,而是将其“拷贝” (copy)。 当属性类型为NSString时,经常用此特质来保护其封装性,因为传递给设置方法的新值有可能指向一个NSMutableString类的实例。这个类是NSString的子类,表示一种可修改其值的字符串,此时若是不拷贝字符串,那么设置完属性之后,字符串的值就可能会在对象不知情的情况下遭人更改。所以,这时就要拷贝一份“不可变” (immutable)的字符串,确保对象中的字符串值不会无意间变动。只要实现属性所用的对象是“可变的” (mutable),就应该在设置新属性值时拷贝一份。


为了理解这种做法,首先要知道,对非集合类对象的copy操作:

在非集合类对象中:对immutable对象进行copy操作,是指针复制,mutableCopy操作时内容复制;对mutable对象进行copy和mutableCopy都是内容复制。用代码简单表示如下:

[immutableObject copy] // 浅复制
[immutableObject mutableCopy] //深复制
[mutableObject copy] //深复制
[mutableObject mutableCopy] //深复制

比如以下代码:

NSMutableString *string = [NSMutableString stringWithString:@"origin"];//copy
NSString *stringCopy = [string copy]; 

查看内存,会发现 string、stringCopy 内存地址都不一样,说明此时都是做内容拷贝、深拷贝。即使你进行如下操作:

[string appendString:@"origion!"]

stringCopy的值也不会因此改变,但是如果不使用copy,stringCopy的值就会被改变。 集合类对象以此类推。 所以,

用@property声明 NSString、NSArray、NSDictionary 经常使用copy关键字,是因为他们有对应的可变类型:NSMutableString、NSMutableArray、NSMutableDictionary,他们之间可能进行赋值操作,为确保对象中的字符串值不会无意间变动,应该在设置新属性值时拷贝一份。

参考链接:iOS 集合的深复制与浅复制

在Objective-C开发中,内存管理是一个重要的话题,尤其是涉及到线程安全和静态变量时。对于静态变量来说,其生命周期贯穿整个程序运行期,不需要每次函数调用时重新分配内存,因此在多线程环境下,它们可以保证数据的一致性和持久性。 参考资源链接:[iOS面试精华:字符串初始化、static特性、线程与进程、堆栈详解](https://wenku.youkuaiyun.com/doc/6bt6nmsgnm?spm=1055.2569.3001.10343) 当涉及到线程安全时,需要特别注意static变量的访问控制。由于static变量在全局范围内是共享的,若多个线程同时访问和修改同一静态变量,可能会导致竞态条件(Race Condition)和数据不一致的问题。为了保证内存安全,可以使用同步机制,如互斥锁(Mutex)串行队列(Serial Dispatch Queue),确保同一时间只有一个线程能够修改静态变量。 另外,在Objective-C中,NSString对象的创建和释放需要遵循内存管理规则。当使用static关键字声明NSString对象时,如果该对象是在栈上创建(即局部静态变量),则由编译器自动管理内存,不需要开发者手动释放;如果是在堆上创建,则需要开发者按照引用计数规则进行适当的内存管理,比如使用`alloc`, `copy`, `retain``strong`属性创建对象,并在适当的时候使用`release``autorelease`进行内存释放。特别是在多线程环境下,应避免因线程间的操作导致引用计数的错误管理。 综上所述,在多线程环境下使用static关键字声明NSString静态变量时,要确保内存安全,应当注意以下几点: 1. 使用同步机制控制对static变量的访问,防止多线程同时操作导致的数据不一致。 2. 若NSString对象是手动创建在堆上的,按照引用计数规则进行内存管理。 3. 若可能,利用自动引用计数(ARC)来管理内存,它能够在编译时插入正确的内存管理代码,减少手动错误。 为了深入理解这些概念,并获得在实际编程中应用的详细信息,推荐阅读《iOS面试精华:字符串初始化、static特性、线程与进程、堆栈详解》。这本书提供了在iOS面试中可能遇到的基础问题的深入探讨,并涵盖了Objective-C字符串处理、内存管理等关键点。 参考资源链接:[iOS面试精华:字符串初始化、static特性、线程与进程、堆栈详解](https://wenku.youkuaiyun.com/doc/6bt6nmsgnm?spm=1055.2569.3001.10343)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值