얕은 복사와 깊은 복사를 이야기하다
복제는 복제 대상이다.카피는 얕은 카피, 깊은 카피 두 종류로 나뉜다.
그럼 copy와 mutable Copy는 어떤 차이가 있을까요?
예를 들어 다음과 같이 설명합니다.
1. NSString
불변 문자열
NSString *str = @"test";
NSString *copyStr = [string copy];
NSMutableString *mutableCopyStr = [string mutableCopy];
NSLog(@"str:%@,%p",str,str);
NSLog(@"copyStr:%@,%p,%d",copyStr,copyStr,copyStr == str);
NSLog(@"mutableCopyStr:%@,%p,%d",muCopyStr,mutableCopyStr,mutableCopyStr == str);
:
str:test,0x10145b098
copyStr:test,0x10145b098,1
muCopyStr:test,0x7feb9355aed0,0
가변 문자열
NSMutableString *str = [[NSMutableString alloc]initWithString:@"test"];
NSString *copyStr = [str copy];
NSMutableString *mutableCopyStr = [str mutableCopy];
NSLog(@"str:%@,%p",str,str);
NSLog(@"copyStr:%@,%p,%d",copyStr,copyStr,copyStr == str);
NSLog(@"mutableCopyStr:%@,%p,%d",mutableCopyStr,mutableCopyStr,mutableCopyStr == str);
:
str:test,0x7fbd90f0f640
copyStr:test,0xa000000747365744,0
muCopyStr:test,0x7fbd90f0be70,0
이를 통해 알 수 있듯이 변하지 않는 문자열에 대해copy는 새로운 대상을 만들지 않고mutableCopy는 새로운 대상을 만들 수 있다.가변 문자열에 대해 copy와mutableCopy는 모두 새로운 대상을 생성합니다. 다만 copy는 변할 수 없는 새로운 대상을 생성하고mutableCopy는 변할 수 있는 새로운 대상을 생성합니다.
이 예를 다시 한 번 보도록 하겠습니다.
NSString *str =@"test";
NSString *copyStr = [str copy];
NSMutableString *mutableCopyStr = [str mutableCopy];
str = @"test0";
// Str , Str ,
NSLog(@"str:%@,%p",str,str);
NSLog(@"copyStr:%@,%p,%d",copyStr,copyStr,copyStr == str);
NSLog(@"mutableCopyStr:%@,%p,%d",mutableCopyStr,mutableCopyStr,mutableCopyStr == str);
str:test0,0x10745e218
copyStr:test,0x10745e098,0
mutableCopyStr:test,0x7fa15beab330,0
NSArray
NSArray와 NSstring은 모두 Foundation 클래스의 하나이기 때문에 상황은 모두 같다
불변 배열
NSArray *arr =@[@"test"];
NSArray *copyArr = [arr copy];
NSMutableArray *mutableCopyArr = [arr mutableCopy];
NSLog(@"arr:%@,%p",arr,arr);
NSLog(@"copyArr:%@,%p,%d",copyArr,copyArr,copyArr == arr);
NSLog(@"mutableCopyArr:%@,%p,%d",mutableCopyArr,mutableCopyArr,mutableCopyArr == arr);
:
arr:(
test
),0x7fdc4161bbd0
copyArr:(
test
),0x7fdc4161bbd0,1
mutableCopyArr:(
test
),0x7fdc4161b160,0
가변 배열
NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",nil];
NSMutableArray *copyArr = [arr copy];
[copyArr removeLastObject];
Xcode
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI removeLastObject]: unrecognized selector sent to instance 0x7fa2da614120'
Foundation 프레임워크에서 자주 사용하는 종류는 NSNumber, NSString, NSArray, NSDictionary, NSMutableArray, NSMutableDictionay, NSMutableString 등copy가 생성한 대상은 변할 수 없고,mutableCopy가 생성한 대상은 변할 수 있는 것이다.
NSMutableArray *arr = [NSMutableArray arrayWithObjects:@"1",@"2",@"3",nil];
NSArray *copyArr = [arr copy];
NSMutableArray *mutableCopyArr = [arr mutableCopy];
arr[0] = @"0";
NSLog(@"arr:%@,%p",arr,arr);
NSLog(@"copyArr:%@,%p,%d",copyArr,copyArr,copyArr == arr);
NSLog(@"mutableCopyArr:%@,%p,%d",mutableCopyArr,mutableCopyArr,mutableCopyArr == arr);
[mutableCopyArr addObject:@"hello"];
NSLog(@"mutableCopyArr:%@,%p,%d",mutableCopyArr,mutableCopyArr,mutableCopyArr == arr);
:
arr:(
0,
2,
3
),0x7f94fbe12550
copyArr:(
1,
2,
3
),0x7ffc12611020,0
mutableCopyArr:(
1,
2,
3
),0x7f94fbe79f80,0
Foundation 프레임워크의 일반 클래스에 대해 다음을 수행합니다.
또 하나 말하자면, 우리는 서면량 문법으로 이런 종류를 많이 만드는 것을 비교적 제창한다
예를 들면 다음과 같습니다.
NSMutableArray *arr = [@[] mutableCopy];
NSMutableDictionary *dict = [@{} mutableCopy];
3. 사용자 정의 대상
일단 Person 클래스를 만들겠습니다.
@interface Person : NSObject
@property (nonatomic, copy)NSString *pid;
@property (nonatomic, copy)NSString *name;
@end
// Person
Person *p = [[Person alloc] init];
p.name = @"joe";
p.pid = @"10";
Person *copyP = [p copy];
Xcode가 실행되면 예상치 못한 오류가 발생합니다.
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Person copyWithZone:]: unrecognized selector sent to instance 0x7ff643641780'
왜냐하면 copyWithZone:이 방법이 실현되지 않았기 때문이다.
@protocol NSCopying
- (id)copyWithZone:(nullable NSZone *)zone;
@end
@protocol NSMutableCopying
- (id)mutableCopyWithZone:(nullable NSZone *)zone;
@end
command+왼쪽 단추를 누르면 이 방법이 NSCopying의 프로토콜 방법임을 알 수 있습니다. 그러면 Person은 NSCopying 방법을 먼저 따라야 합니다.
@interface Person : NSObject
@property (nonatomic, copy)NSString *pid;
@property (nonatomic, copy)NSString *name;
@end
@implementation Person
- (id)copyWithZone:(NSZone *)zone{
return @"test";
}
// Person
Person *p = [[Person alloc] init];
p.name = @"joe";
p.pid = @"10";
Person *copyP = [p copy];
NSLog(@"p = %p copyP = %p", p, copyP);
p = 0x7fab996acf50 copyP = 0x10ab5c088
결과적으로 copyWithZone: (NSZone*)zone은 실제적으로 새로운 대상에게 메모리 공간을 재분배했고 반환은 문자열이기 때문에 copyP는 실제적으로 NSString 클래스의 대상이다
@implementation Person
- (id)copyWithZone:(NSZone *)zone{
// p zone, alloc
// Person *p = [[Person alloc]init];
// Person , Person allocWithZone [self class] allocWithZone:
// Person *p = [[Person allocWithZone:zone]init];
Person *p = [[[self class] allocWithZone:zone] init];
p.name = self.name;
p.pid = self.pid;
return p;
}
// Person
Person *p = [[Person alloc] init];
p.name = @"joe";
p.pid = @"10";
Person *copyP = [p copy];
NSLog(@"p = %p copyP = %p", p, copyP);
NSLog(@"name = %@, pid = %@", copyP.name, copyP.pid);
NSLog(@"p.name :%p,copyP.name :%p",p.name,copyP.name);
p = 0x7fbfcb40e470 copyP = 0x7fbfcb418330
name = joe, pid = 10
p.name :0x10489d2a8,copyP.name :0x10489d2a8
copyWithZone
은 얕은 복사본이고 사용자 정의 대상은 이 방법을 다시 쓴다.copy를 진행할 때 새로운 대상에게 새로운 메모리 주소를 분배하고 mutableCopyWithZone
은 깊은 복사본이고 새로운 대상에게 새로운 메모리 주소를 분배하기 때문에 [p copy]
을 할 때 NSCopying
프로토콜을 따라 copyWithZone
을 다시 쓰는 방법, [p mutableCopy]
을 NSMutableCopying
으로 할 때 mutableCopyWithZone
을 따라 다시 쓰는 방법도 마찬가지다.- (id)mutableCopyWithZone:(NSZone *)zone{
Person *p = [[[self class] allocWithZone:zone] init];
p.name = self.name;
p.pid = self.pid;
return p;
}
하위 클래스가 상위 클래스를 상속할 때 하위 클래스도 상위 NSCopying 프로토콜을 따른다. 이 때 하위 클래스에서 copyWithZone 방법을 다시 쓰지 않아도 된다.그러나 부류에서runtime를 사용하여 모든 구성원 속성 목록을 훑어보고 값을 부여할 수 있지만 부류의 속성은 값을 부여하지 못합니다.
@interface Person : NSObject
@property (nonatomic, copy)NSString *pid;
@property (nonatomic, copy)NSString *name;
@end
@implementation Person
- (id)copyWithZone:(NSZone *)zone{
id obj = [[[self class]allocWithZone:zone]init];
unsigned int outCount;
Ivar * ivars = class_copyIvarList([self class], &outCount);
for (int i = 0; i < outCount; i ++) {
Ivar ivar = ivars[i];
NSString * key = [NSString stringWithUTF8String:ivar_getName(ivar)];
id value = [self valueForKey:key];
[obj setValue:value forKey:key];
}
free(ivars);
return obj;
}
@interface Student : Person
@property (nonatomic, copy) NSString *age;
@end
// Student
Student *s = [[Student alloc]init];
s.name = @"marry";
s.age = @"18";
Student *copyS = [s copy];
NSLog(@"s = %p copyS = %p", s, copyS);
NSLog(@"name = %@ age = %@", copyS.name, copyS.age);
:
s = 0x7fa83a608ce0 copyS = 0x7fa83a61a100
name = (null) age = 18
이럴 때 속성을 보면 스트롱과 코피가 이해하기 쉬워요. 예를 들면 저희가 Person 클래스에 속성을 하나 더 넣었어요.
@interface Person : NSObject
@property (nonatomic, copy)NSString *pid;
@property (nonatomic, copy)NSString *name;
@property (nonatomic, copy) NSMutableArray *arr;
@end
// Person
Person *p = [[Person alloc] init];
p.name = @"joe";
p.pid = @"10";
NSMutableArray *arr = [@[@"test"] mutableCopy];
p.arr = arr;
[arr addObject:@"hell0"];
Person *copyP = [p copy];
NSLog(@"arr:%p, p.arr:%@ %p,
copyP.arr:%@ %p",arr,p.sign,p.arr,copyP.arr,copyP.arr);
arr:0x7fddea4358a0,p.arr:(
test
),0x7fddea43d0b0,
copyP.arr:(
test
),0x7fddea43d0b0
@property 본질: ivar (실례 변수), 접근 방법 (access method = getter + setter)
copy로 수식할 때,self.arr 실제 실현 이 setter 방법
- (void)setArr:(NSMutableArray *)arr{
_arr = [arr copy];
}
[p.arr addObject:@"hell0"];
[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7ff3b94ee1a0'
그래서 셀프.arr는 여전히 변할 수 없습니다. @property에 변할 수 있는 속성을 추가하지 마십시오.
그러면 스트롱으로 한번 꾸며볼게요.
@property (nonatomic, strong) NSMutableArray *arr;
// Person
Person *p = [[Person alloc] init];
p.name = @"joe";
p.pid = @"10";
NSMutableArray *arr = [@[@"test"] mutableCopy];
p.arr = arr;
[arr addObject:@"hell0"];
Person *copyP = [p copy];
NSLog(@"arr:%p, p.arr:%@ %p,
copyP.arr:%@ %p",arr,p.sign,p.arr,copyP.arr,copyP.arr);
arr:0x7fbbf8503cc0,p.arr:(
test,
hell0
),0x7fbbf8503cc0,
copyP.arr:(
test,
hell0
),0x7fbbf8503cc0
실제적으로strong으로 수식할 때,self.arr 이 setter 방법을 실현합니다
- (void)setArr:(NSMutableArray *)arr{
_arr = arr
}
그래서strong으로 수식할 때,self.arr는 가변 수조로 주소가 변경되지 않았습니다. arr가 바뀔 때self.arr도 바뀔 거야.
위에서 알 수 있듯이 copyWithZone: 얕은 복제가 발생하기 때문에 이런 방법은 1층 깊이 복제만 발생할 수 있다. 만약에 집합 안의 원소가 여전히 집합이라면 하위 집합 안의 원소는 깊이 복제되지 않고 하위 집합 안의 원소 바늘만 복제한다.
이 예를 한번 봅시다.
NSMutableString * testStr = [NSMutableString stringWithString:@"test"];
NSArray *arr = @[testStr];
NSArray *copyArr = [arr copy];
NSMutableArray *mutableCopyArr = [arr mutableCopy];
NSArray *arr2 = [[NSArray alloc]initWithArray:arr copyItems:YES];
[testStr appendString:@" hello"];
NSLog(@" arr.firstObject = %p,
copyArr.firstObject= %p,
mutableCopyArr.firstObject= %p,
arr2.firstObject =%p",arr.firstObject, copyArr.firstObject, mutableCopyArr.firstObject, arr2.firstObject);
NSLog(@"arr %@,
copyArr %@,
mutableCopyArr %@,
arr2 %@",arr, copyArr, mutableCopyArr, arr2);
:
arr.firstObject = 0x7fbfd27069a0,
copyArr.firstObject = 0x7fbfd27069a0,
mutableCopyArr.firstObject = 0x7fbfd27069a0,
arr2.firstObject = 0xa000000747365744
arr (
"test hello"
),
copyArr (
"test hello"
),
mutableCopyArr (
"test hello"
),
arr2 (
test
)
initWithArray:copyItems:YES, initWithDictionary copyItems:YES 사용
Tier 2 에만 복제할 수 있으며, 더 깊은 부분이 있으면 완전히 복제할 수 없습니다.
NSMutableString * testStr = [NSMutableString stringWithString:@"test"];
NSMutableArray *testArr = [NSMutableArray arrayWithObject:testStr];
NSArray *arr = @[testArr];
NSArray *copyArr = [arr copy];
NSMutableArray *mutableCopyArr = [arr mutableCopy];
NSArray *arr2 = [[NSArray alloc]initWithArray:arr copyItems:YES];
[testStr appendString:@" hello"];
NSLog(@" arr.firstObject = %p,
copyArr.firstObject= %p,
mutableCopyArr.firstObject =%p,
arr2.firstObject =%p",arr.firstObject, copyArr.firstObject, mutableCopyArr.firstObject, arr2.firstObject);
NSLog(@"arr %@,
copyArr %@,
mutableCopyArr %@,
arr2 %@",arr, copyArr, mutableCopyArr, arr2);
:
arr.firstObject = 0x7fb50bf0cf60,
copyArr.firstObject = 0x7fb50bf0cf60,
mutableCopyArr.firstObject = 0x7fb50bf0cf60,
arr2.firstObject = 0x7fb50bf002f0
arr (
(
"test hello"
)
),
copyArr (
(
"test hello"
)
),
mutableCopyArr (
(
"test hello"
)
),
arr2 (
(
"test hello"
)
)
완전 심도 복제를 실현하려면 압축 파일을 사용해서 해제해야 한다.아카이브와 아카이브를 사용하려면 NSCoding 프로토콜을 준수해야 합니다.
NSMutableString * testStr = [NSMutableString stringWithString:@"test"];
NSMutableArray *testArr = [NSMutableArray arrayWithObject:testStr];
NSArray *arr = @[testArr];
NSArray *copyArr = [arr copy];
NSMutableArray *mutableCopyArr = [arr mutableCopy];
NSArray *arr2 = [[NSArray alloc]initWithArray:arr copyItems:YES];
//
NSArray *arr3 = [NSKeyedUnarchiver unarchiveObjectWithData:[NSKeyedArchiver archivedDataWithRootObject:arr]];
[testStr appendString:@" hello"];
id firstObject1 = [arr firstObject][0];
id firstObject2 = [copyArr firstObject][0];
id firstObject3 = [mutableCopyArr firstObject][0];
id firstObject4 = [arr2 firstObject][0];
id firstObject5 = [arr3 firstObject][0];
NSLog(@" arr.firstObject.firstObject = %p,
copyArr.firstObject.firstObject = %p,
mutableCopyArr.firstObject.firstObject = %p,
arr2.firstObject.firstObject = %p,arr3.firstObject.firstObject = %p",firstObject1, firstObject2, firstObject3, firstObject4,firstObject5);
NSLog(@"arr %@,
copyArr %@,
mutableCopyArr %@,
arr2 %@,
arr3 %@",arr, copyArr, mutableCopyArr,arr2,arr3);
:
arr.firstObject.firstObject = 0x7fd4d271e8d0, copyArr.firstObject.firstObject = 0x7fd4d271e8d0,
mutableCopyArr.firstObject.firstObject = 0x7fd4d271e8d0,
arr2.firstObject.firstObject = 0x7fd4d271e8d0,
arr3.firstObject.firstObject = 0x7fd4d272b360
arr (
(
"test hello"
)
),
copyArr (
(
"test hello"
)
),
mutableCopyArr (
(
"test hello"
)
),
arr2 (
(
"test hello"
)
),
arr3 (
(
test
)
)
우리는 깊이 있는 복사를 고려할 때 집합된 구조 요소가 다른 집합을 끼워 넣지 않으면mutableCopy는 모든 내용을 복제합니다. 집합 요소가 집합이든 집합이든 압축 파일의 해제를 고려하여 완전한 깊이 복사를 실현해야 합니다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.