一.copy和mutableCopy
深拷貝和淺拷貝的區別:
深拷貝就是指針和內存地址都複製了,開闢了新的內存空間 淺拷貝只複製指針
深拷貝不會影響被拷貝對象的引用計數 淺拷貝會影響被拷貝對象的引用計數
- 可變對象的copy和mutableCopy都是深拷貝
- 不可變對象的copy是淺拷貝 mutableCopy是深拷貝
- copy方法返回的都是不可變對象
// 1.本尊可變 copy mutableCopy出來的都可變,深拷貝
NSMutableString *strM = [NSMutableString stringWithString:@"123"];
NSMutableString *str1 = [strM copy];
NSMutableString *str2 = [strM mutableCopy];
// 0x100306850 0x33323135 0x10062a3c0 深拷貝
NSLog(@"%@ %@ %@", strM, str1,str2);
NSLog(@"%p %p %p", strM, str1,str2);
//注意:如果直接修改指針,是可以通過id的方式間接修改,不安全
NSString *str2 = strM;
//0x100306850 0x100306850
NSLog(@"%@ %@", strM, str2);
NSLog(@"%p %p", strM, str2);
// M & !M
NSLog(@"%@", [str2 class]);//__NSCFString 不可變的
id str3 = str2;//搞一個一模一樣的指針也指向同一個對象
NSLog(@"%@", [str3 class]);//__NSCFString 不可變的
//0x100306850 0x100306850
NSLog(@"%p %p", str3, str2);
[str3 setString:@"hello"];
//不可變的str2改成了hello,因爲他的本尊是可變的,所以還可以修改
NSLog(@"%@", str2);
總結:最常用的也是避免不必要麻煩的就是當開發中遇到臨時變量是可變的,而成員變量是不可變的情況下,
應該使用copy,會很安全
// 3.本尊不可變 copy出來的不可變 mutableCopy出來的可變
NSString *strM = @"123";
NSMutableString *str1 = [strM copy];//淺拷貝
NSMutableString *str2 = [strM mutableCopy];//深拷貝
//0x100005298 0x100005298 0x10067e630
NSLog(@"%@ %@ %@", strM, str1,str2);
NSLog(@"%p %p %p", strM, str1,str2);
NSString *str = @"hello";
// copy原模原樣的複製 本尊不能改你就不能改 本準能改就能改
NSMutableString *strM = [str copy];
// [strM appendString:@" 123"]; //會報錯,因爲strM不能改雖然是NSMutableString但是你還是不能改
NSMutableString *str2 = [strM mutableCopy];
//0x100578f30 0x33323135 0x100578fe0 深拷貝
NSLog(@"%@ %@ %@", strM, str,str2);
NSLog(@"%p %p %p", strM, str,str2);
// mutableCopy複製出一個可變的傢伙 無論你可變不可變,複製的出來的都是可變的
NSMutableString *strM1 = [str mutableCopy];
[strM1 appendString:@" 123"]; //不報錯
//hello hello 123
NSLog(@"%@ %@ %@", str, strM, strM1);
//0x100005318 0x100005318 0x100301490
NSLog(@"%p %p %p", str, strM, strM1);
//4.本尊不可變 copy出來的不可變 mutableCopy出來的可變
NSString *str = @"hello";
NSString *str1 = [str copy];
NSString *str2 = [str mutableCopy];
//前面兩個一樣,最後一個不一樣
// hello hello hello
//0x100005318 0x100005318 0x100302840
NSLog(@"%@ %@ %@", str, str1, str2);
NSLog(@"%p %p %p", str, str1, str2);
二.對象中的使用
void Person2Person()
{
//自定義對象都是可變的 所以拷貝的對象都是深拷貝
Person *p = [[Person alloc] init];
p.name = @"zhang";
Person *p1 = [p copy];
p1.name = @"li";
//0x1003043d0 : name zhang Person 0x1003048f0 : name li
NSLog(@"%@ %@", p, p1);
//0x1003043d0 0x1003048f0 深拷貝
NSLog(@"%p %p", p, p1);
}
void Person3Person()
{
Student *s = [[Student alloc] init];
s.name = @"zhang";
Student *s1 = [s copy];
s1.name = @"li";
s1.No = 10; //如果不寫student的copyWithZone方法會崩潰
NSLog(@"%@ %@", s, s1);
}
總結:1.自定義對象都是可變的,所以都是深拷貝 2.想要拷貝就要遵守<NSCopying>協議,並且子類和父類都要實現協議方法
代碼如下:
Person代碼
// Person.h
#import <Foundation/Foundation.h>
// 自定義對象都是可變的
@interface Person : NSObject <NSCopying>
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) NSInteger age;
@end
// Person.m
#import "Person.h"
@implementation Person
- (id)copyWithZone:(NSZone *)zone
{
Person *p = [[[self class] allocWithZone:zone] init];
p.name = self.name;
p.age = self.age;
return p;
}
- (NSString *)description
{
return [NSString stringWithFormat:@"%@ %p : name %@", self.class, self, self.name];
}
@end
Student代碼
// Student.h
#import "Person.h"
@interface Student : Person
@property (nonatomic, assign) int No;
@end
// Student.m
#import "Student.h"
@implementation Student
- (id)copyWithZone:(NSZone *)zone
{
Student *s = [super copyWithZone:zone];
s.No = self.No;
return s;
}
@end