1205 字
6 分钟
【iOS】对象复制与属性关键字

目录

对象复制

一、copy与mutableCopy方法

二、NSCopying和NSmutableCopying协议

三、深复制与浅复制

按照类型说明:

非容器类对象的深拷贝与浅拷贝

不可变字符串

可变类型字符串

容器类对象的深浅拷贝

自定义类型的拷贝

容器类对象的深拷贝

归档与解档代码实现

属性关键字

1 原子性

2 读写权限

3. 内存管理

assign

weak

unsafe_unretained

retain

strong

copy

4. 修饰变量关键字

常量(const)和宏定义(define)的区别:

Q&A:

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

Q:以下代码会出现什么问题?

Q:assign 和 weak 关键字的区别有哪些?

Q:atomic 修饰的属性是怎么样保存线程安全的?

Q:weak和assign的区别?

对象复制#

一、copy与mutableCopy方法#

copy方法用于复制对象的副本,复制下来的该副本是不可修改的,哪怕是调用NSMutableString的copy方法也不可修改。

而mutableCopy方法复制下来的副本是可修改的,即使被复制的对象原本是不可修改的。例如调用mutableCopy方法复制NSString的,返回的是一个NSMutableString对象。

以下用代码演示copy和mutableCopy方法的功能:

#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
@autoreleasepool {
//copy与mutableCopy
NSMutableString *book = [NSMutableString stringWithString: @"疯狂iOS讲义"];
NSMutableString *bookCopy = [book mutableCopy]
[bookCopy replaceCharactersInRange: NSMakeRange(2, 3) withString: @"Android"];//复制后的bookCopy副本是可以修改的,这里做个修改,对原字符串的值也没有影响
NSLog(@"book的值为:%@",book);//原值
NSLog(@"bookCopy的值为:%@",bookCopy);//副本修改后的值
NSString *str = @"fkit";//定义一个str字符串
NSMutableString *strCopy = [str mutableCopy];//用mutableCopy给str复制一个副本
[strCopy appendString:@".org"];//向可变字符串后面追加字符串
NSLog(@"%@",strCopy);
NSMutableString *bookCopy2 = [book copy];//用copy方法复制一个book的副本(这个副本不可变)
[bookCopy2 appendString:@"aa"];//这里会报错,因为copy创建的副本不可变,修改了就崩了
}
return 0;
}
### 二、NSCopying和NSmutableCopying协议
当我们想将自定义类用上一节的两个方法复制副本时,我们可能会直接创建完对象后用”类名* 对象2 = [对象1 copy];“这样的格式来复制副本,但实际上直接这样复制是不对的,会报错说找不到copyWithZone:方法,mutableCopy也是一样。因此我们可以看出,自定义类是不能直接调用这两个方法来复制自身的。
这是为什么呢?是因为当程序调用copy/mutableCopy方法复制时,程序底层需要调用copyWithZone:/mutableCopyWithZone:方法来完成复制的工作,并返回这两个方法的值。因此为了保证可以复制,需要在自定义类的接口部分声明NSCopying/NSMutableCopying协议,然后再类的实现部分增加copyWithZone:/mutableCopyWithZone:方法,因此,对自定义对象的复制应该如下所示:
接下来,我们以一个自定义的Person类为例,支持copy和mutablecopy:
```objective-c
#import <Foundation/Foundation.h>
@interface Person : NSObject <NSCopying, NSMutableCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
@implementation Person
// 实现 copy(返回不可变副本)
- (id)copyWithZone:(NSZone *)zone {
Person *copy = [[[self class] allocWithZone:zone] init];
copy.name = [self.name copy];
copy.age = self.age;
return copy;
}
// 实现 mutableCopy(返回可变副本)
- (id)mutableCopyWithZone:(NSZone *)zone {
Person *copy = [[[self class] allocWithZone:zone] init];
copy.name = [self.name mutableCopy]; // 注意生成可变副本
copy.age = self.age;
return copy;
}
@end
int main(int argc, const char * argv[]) {
@autoreleasepool {
Person *p1 = [[Person alloc] init];
p1.name = @"Tom";
p1.age = 18;
Person *p2 = [p1 copy]; // 调用 copyWithZone
Person *p3 = [p1 mutableCopy]; // 调用 mutableCopyWithZone
NSLog(@"原始:%@ %ld", p1.name, p1.age);
NSLog(@"copy:%@ %ld", p2.name, p2.age);
NSLog(@"mutableCopy:%@ %ld", p3.name, p3.age);
}
return 0;
}
### 三、深复制与浅复制
深复制和浅复制是面向对象编程中非常重要的概念。
浅复制:仅复制对象的指针地址,多个变量共享同一个对象。
深复制: 不仅复制指针,还会复制整个对象内容,使得原对象和副本完全独立。
举个例子:
```objective-c
NSMutableString *str1 = [NSMutableString stringWithString:@"Hello"];
NSMutableString *str2 = str1; // 浅复制(赋值)
// 修改 str1,str2 也变了
[str1 appendString:@" World"];

因此总而言之,浅拷贝就是创建一个副本,对内存地址的复制。深拷贝就是创建一个副本,对内容完全复制。原始对象与副本对象内存地址不同。

按照类型说明:#

非容器类对象的深拷贝与浅拷贝#

不可变字符串#
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSString* str1 = @"dddddd";
NSString* str2 = [str1 copy];
NSString* str3 = [str1 mutableCopy];
NSMutableString* str4 = [str1 copy];
NSMutableString* str5 = [str1 mutableCopy];
NSLog(@"str1:%p", str1);
NSLog(@"str2:%p", str2);
NSLog(@"str3:%p", str3);
NSLog(@"str4:%p", str4);
NSLog(@"str5:%p", str5);
}
return 0;
}

图片

得出结论: 不可变字符串,只要是copy就是浅拷贝,mutableCopy是深拷贝。tips:我们用NSString stringWithstring 方式创建的是一个常量区字符串。

图片


原文发布于 CSDN:【iOS】对象复制与属性关键字

【iOS】对象复制与属性关键字
https://www.tommywutong.cn/posts/csdn-import/csdn-151194120-ios-/
作者
TommyWu
发布于
2025-09-27
许可协议
CC BY-NC-SA 4.0