[objective-c] NSString 속성 : 복사 또는 유지?

하자 내가라는 클래스가 있다고 가정 SomeClassstring속성 이름을 :

@interface SomeClass : NSObject
{
    NSString* name;
}

@property (nonatomic, retain) NSString* name;

@end

본인은 이름에 할당 될 수 NSMutableString있으며이 경우 잘못된 행동으로 이어질 수 있음을 이해합니다 .

  • 일반적으로 문자열의 경우 항상copy 대신 속성 을 사용하는 것이 좋습니다 retain.
  • “복사 된”속성이 “유지 된”속성보다 덜 효율적입니까?


답변

NSCopying프로토콜 을 준수하는 불변 값 클래스 인 속성의 경우 거의 항상 선언에 지정해야 copy합니다 @property. retain이러한 상황에서 지정 은 거의 원하지 않습니다.

그 이유는 다음과 같습니다.

NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];

Person *p = [[[Person alloc] init] autorelease];
p.name = someName;

[someName setString:@"Debajit"];

의 현재 값 Person.name속성은 속성이 선언되는지 여부에 따라 상이 할 것이다 retain또는 copy그것이 될 것이다 – @"Debajit"속성이 표시되어있는 경우 retain만, @"Chris"속성이 표시되어있는 경우 copy.

거의 모든 경우 에 객체의 속성을 뒤에서 변경 하지 않으려면 객체를 나타내는 속성을 표시해야합니다 copy. (그리고 사용하는 대신 세터를 직접 작성하는 경우 @synthesize실제로 copy대신 사용 하는 것을 기억해야 retain합니다.)


답변

NSString에는 복사를 사용해야합니다. Mutable이면 복사됩니다. 그렇지 않은 경우 유지됩니다. 정확히 앱에서 원하는 의미론 (유형이 최선을 다하도록하십시오).


답변

일반적으로 문자열의 경우 항상 retain 대신 copy 속성을 사용하는 것이 좋습니다?

예-일반적으로 항상 복사 속성을 사용하십시오.

NSString 속성NSString 인스턴스 또는 NSMutableString 인스턴스를 전달할 수 있기 때문에 전달되는 값이 불변 또는 변경 가능한 객체인지 실제로 확인할 수 없기 때문입니다.

“복사 된”속성이 “유지 된”속성보다 덜 효율적입니까?

  • 속성에 NSString 인스턴스 가 전달 되면 대답은 ” 아니오 “입니다. 복사는 유지하는 것보다 덜 효율적입니다.
    NSString은 실제로 복사를 수행 할 수 없을만큼 똑똑하기 때문에 효율성이 떨어집니다.

  • 속성에 NSMutableString 인스턴스 가 전달 되면 대답은 ” “입니다. 복사가 보유보다 효율적이지 않습니다.
    (실제 메모리 할당 및 복사가 발생해야하기 때문에 효율성이 떨어지지 만 이는 바람직한 것입니다.)

  • 일반적으로 “복사 된”속성은 효율성이 떨어질 가능성이 있지만 NSCopying프로토콜을 사용 하면 유지하는 것처럼 “복사하는만큼”효율적인 클래스를 구현할 수 있습니다. NSString 인스턴스 가 이에 대한 예입니다.

일반적으로 (NSString뿐만 아니라) “retain”대신 “copy”를 언제 사용해야합니까?

copy속성의 내부 상태가 경고없이 변경되지 않도록하려면 항상 사용해야 합니다. 불변 객체의 경우에도 올바르게 작성된 불변 객체는 복사를 효율적으로 처리합니다 (불변성과 및 다음 섹션 참조 NSCopying).

retain객체에 성능상의 이유가있을 수 있지만 유지 보수 오버 헤드가 있습니다. 코드 외부에서 내부 상태가 변경 될 가능성을 관리해야합니다. 그들이 말한대로-마지막으로 최적화하십시오.

그러나 나는 나의 수업을 불변으로 썼다 – 단지 그것을 “유지”할 수 없는가?

사용 안함 copy. 클래스가 실제로 변경 불가능한 경우, 사용될 NSCopying때 클래스 자체를 반환하도록 프로토콜을 구현하는 것이 가장 좋습니다 copy. 이렇게하면 :

  • 수업의 다른 사용자는 사용할 때 성능 이점을 얻을 수 있습니다 copy.
  • copy주석은 자신의 코드를 유지 관리하기 쉽게 해줍니다 . 주석은 copy이 객체가 다른 곳에서이 객체의 상태 변경에 대해 걱정할 필요가 없음을 나타냅니다.

답변

이 간단한 규칙을 따르려고합니다.

  • 객체 속성을 할당 할 때 객체 의 을 유지하고 싶 습니까? copy를 사용 하십시오 .

  • 나는 붙잡고 싶어 개체나는 그것의 내부 값은 어떤 상관 없어 현재 또는 미래에있을 것인가? 강력하게 사용하십시오 .

예를 들면 : “Lisa Miller”( 사본 ) 라는 이름 을 붙잡고 싶거나 Lisa Miller ( 강력한 ) 사람 을 붙잡고 싶습니다 . 그녀의 이름은 나중에 “Lisa Smith”로 변경 될 수 있지만 여전히 같은 사람이 될 것입니다.


답변

이 예제를 통해 복사 및 유지는 다음과 같이 설명 될 수 있습니다.

NSMutableString *someName = [NSMutableString stringWithString:@"Chris"];

Person *p = [[[Person alloc] init] autorelease];
p.name = someName;

[someName setString:@"Debajit"];

속성이 copy 유형 인 경우,

[Person name]문자열의 내용을 보유 할 문자열에 대해 새 사본이 작성 됩니다 someName. 이제 someName문자열 에 대한 작업은 영향을 미치지 않습니다 [Person name].

[Person name]someName문자열은 서로 다른 메모리 주소를해야합니다.

그러나 유지하는 경우

둘 다 [Person name]somename 문자열과 동일한 메모리 주소를 보유하며 somename 문자열의 유지 횟수는 1 씩 증가합니다.

따라서 somename 문자열의 변경 사항은 문자열에 반영됩니다 [Person name].


답변

속성 선언에 ‘복사’를 넣는 것은 힙의 객체가 참조로 전달되는 객체 지향 환경을 사용하여 비행하는 것입니다. 여기서 얻는 이점 중 하나는 객체를 변경할 때 해당 객체에 대한 모든 참조입니다 최신 변경 사항을 참조하십시오. 많은 언어가 ‘ref’또는 유사한 키워드를 제공하여 값 유형 (예 : 스택의 구조)이 동일한 동작의 이점을 얻을 수 있도록합니다. 개인적으로 필자는 복사를 거의 사용하지 않고 할당 된 객체의 변경 사항으로부터 속성 값을 보호해야한다고 생각되면 할당하는 동안 해당 객체의 복사 방법을 호출 할 수 있습니다. 예 :

p.name = [someName copy];

물론 해당 속성이 포함 된 객체를 디자인 할 때 할당이 복사되는 패턴에서 디자인이 이점을 얻는 지 여부 만 알 수 있습니다. Cocoawithlove.com 은 다음과 같이 말합니다.

“세터 매개 변수를 변경할 수 있지만 경고없이 속성의 내부 상태를 변경할 수없는 경우 복사 접근 자를 사용해야합니다.”-예기치 않은 변경 값을 참을 수 있는지 여부에 대한 판단은 모두 본인의 것입니다. 이 시나리오를 상상해보십시오.

//person object has details of an individual you're assigning to a contact list.

Contact *contact = [[[Contact alloc] init] autorelease];
contact.name = person.name;

//person changes name
[[person name] setString:@"new name"];
//now both person.name and contact.name are in sync.

이 경우 복사를 사용하지 않고 접점 오브젝트는 새 값을 자동으로 가져옵니다. 그러나 우리가 그것을 사용했다면, 변경 사항을 감지하고 동기화했는지 수동으로 확인해야합니다. 이 경우 의미를 유지하는 것이 바람직 할 수 있습니다. 다른 경우에는 복사가 더 적합 할 수 있습니다.


답변

@interface TTItem : NSObject
@property (nonatomic, copy) NSString *name;
@end

{
    TTItem *item = [[TTItem alloc] init];
    NSString *test1 = [NSString stringWithFormat:@"%d / %@", 1, @"Go go go"];
    item.name = test1;
    NSLog(@"-item.name: point = %p, content = %@; test1 = %p", item.name, item.name, test1);
    test1 = [NSString stringWithFormat:@"%d / %@", 2, @"Back back back"];
    NSLog(@"+item.name: point = %p, content = %@, test1 = %p", item.name, item.name, test1);
}

Log:
    -item.name: point = 0x9a805a0, content = 1 / Go go go; test1 = 0x9a805a0
    +item.name: point = 0x9a805a0, content = 1 / Go go go, test1 = 0x9a84660