[objective-c] @synthesize를 언제 명시 적으로 사용해야합니까?

내가 아는 한, XCode 4.4 이후로 @synthesize속성 접근 자를 자동 생성합니다. 그러나 방금에 대한 코드 샘플을 읽었 NSUndoManager으며 코드에서이 @synthesize명시 적으로 추가 되었음을 알 수 있습니다. 처럼:

@interface RootViewController  ()

@property (nonatomic, strong) NSDateFormatter *dateFormatter;
@property (nonatomic, strong) NSUndoManager *undoManager;

@end

@implementation RootViewController
//Must explicitly synthesize this
@synthesize undoManager;

지금 당황 스럽습니다 … 언제 @synthesize코드 에 명시 적으로 추가해야 합니까?



답변

많은 답변이 있지만 큰 혼란도 있습니다. 나는 주문을하려고 노력할 것입니다 (또는 엉망진창을 늘리십시오, 우리는 보게 될 것입니다 …)

  1. Xcode에 대한 이야기는 그만합시다. Xcode는 IDE 입니다. clang은 컴파일러 입니다. 우리가 논의하고있는이 기능 은 속성의 자동 합성 이라고 하며 Xcode에서 사용하는 기본 컴파일러 인 clang 에서 지원 하는 Objective-C 언어 확장 입니다.
    명확히하기 위해, Xcode에서 gcc로 전환하면이 기능의 이점을 얻지 못할 것입니다 (Xcode 버전에 관계없이). 같은 방식으로 텍스트 편집기를 사용하고 명령 줄에서 clang을 사용하여 컴파일하는 경우 의지.

  2. 자동 합성 기능 덕분에 속성을 명시 적으로 합성 할 필요가 없습니다. 컴파일러에 의해 자동으로 합성되므로

    @synthesize propertyName = _propertyName
    

    그러나 몇 가지 예외가 있습니다.

    • 사용자 정의 getter 및 setter가있는 readwrite 속성

      getter 및 setter 사용자 지정 구현을 모두 제공 할 때 속성이 자동으로 합성되지 않습니다.

    • 사용자 정의 getter가있는 읽기 전용 속성

      readonly 속성에 대한 사용자 정의 getter 구현을 제공 할 때 이것은 자동으로 합성되지 않습니다.

    • @동적

      사용하는 경우 @dynamic propertyName,이 건물은 자동으로 (매우 명백 이후 합성되지 않습니다 @dynamic@synthesize상호 배타적입니다)

    • @protocol에 선언 된 속성

      프로토콜을 준수 할 때 프로토콜이 정의하는 속성은 자동으로 합성되지 않습니다.

    • 카테고리에 선언 된 속성

      이것은 @synthesize지시문이 컴파일러에 의해 자동으로 삽입되지 않는 경우이지만이 속성도 수동으로 합성 할 수 없습니다. 범주는 속성을 선언 할 수 있지만 범주는 ivar를 만들 수 없으므로 전혀 합성 할 수 없습니다. 완전성을 위해 Objective-C 런타임을 사용하여 속성 합성을 위조 할 수 있다는 점을 추가하겠습니다 .

    • 재정의 된 속성 (clang-600.0.51 이후 새로운 기능, Xcode 6과 함께 제공, Marc Schlüpmann에게 감사드립니다)

      슈퍼 클래스의 속성을 재정의 할 때 명시 적으로 합성해야합니다.

속성을 합성하면 백업 ivar가 자동으로 합성되므로 명시 적으로 선언하지 않는 한 속성 합성이 누락 된 경우 ivar도 누락됩니다.

마지막 세 가지 경우를 제외하고 일반적인 철학은 속성에 대한 모든 정보를 수동으로 지정할 때마다 (모든 접근 자 메서드를 구현 @dynamic하거나을 사용하여 ) 컴파일러가 속성에 대한 모든 권한을 원한다고 가정하고 자동 합성을 비활성화한다는 것입니다. 그것.

위에 나열된 경우를 제외하고 명시 @synthesize적의 유일한 다른 용도 는 다른 ivar 이름을 지정하는 것입니다. 그러나 규칙이 중요하므로 항상 기본 이름을 사용하는 것이 좋습니다.


답변

명시 적으로 사용하지 않으면 @synthesize컴파일러는 다음과 같은 방식으로 속성을 이해합니다.

@synthesize undoManager=_undoManager;

그러면 다음과 같은 코드를 작성할 수 있습니다.

[_undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter

이것은 일반적인 관습입니다.

당신이 쓰면

@synthesize undoManager;

당신은 할 것 :

[undoManager doSomething]; // iVar
[self.undoManager doSomethingElse]; // Use generated getter

@synthesize더 이상 필수가 아니기 때문에 개인적으로 사용을 중지 합니다. 나를 위해 사용하는 유일한 이유는 @synthesize을 연결하는 iVarA를 @property. 특정 getter 및 setter를 생성하려는 경우. 그러나 주어진 코드에는 아무것도 없습니다. iVar이것은 @synthesize쓸모가 없다고 생각합니다 . 하지만 이제는 새로운 질문이 “언제 사용해야 iVar합니까?” 라고 생각합니다.이 질문에 대해서는 “절대”라는 답변이 없습니다!


답변

언제 @synthesize코드 에 명시 적으로 추가해야 합니까?

일반적으로 필요한 경우 : 필요한 경우에는 결코 맞지 않을 것입니다.

그래도 유용하다고 생각되는 경우가 하나 있습니다.

커스텀 getter와 setter를 모두 작성하고 있지만 인스턴스 변수가이를 지원하고 싶다고 가정 해 보겠습니다. (원자 속성의 경우 이는 사용자 지정 setter를 원하는 것만 큼 간단합니다. 단원 속성에 대해 setter를 지정하면 컴파일러가 getter를 작성하지만 원자 속성은 지정하지 않습니다.)

이걸 고려하세요:

@interface MyObject:NSObject
@property (copy) NSString *title;
@end

@implementation MyObject

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

_title존재하지 않기 때문에 작동하지 않습니다. getter 또는 setter를 모두 지정 했으므로 Xcode는 (올바르게) 이에 대한 백업 인스턴스 변수를 생성하지 않습니다.

여기에 이미지 설명 입력

존재하도록하기위한 두 가지 선택이 있습니다. 다음 중 하나로 변경할 수 있습니다 @implementation.

@implementation MyObject {
    NSString *_title;
}

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

또는 다음과 같이 변경하십시오.

@implementation MyObject

@synthesize title = _title;

- (NSString *)title {
    return _title;
}
- (void)setTitle:(NSString *)title {
    _title = [title copy];
}

@end

즉, 합성이 실제 목적을위한 것은 절대 필요하지 않지만 *, getter / setter를 제공 할 때 속성 지원 인스턴스 변수 를 정의하는 데 사용할 수 있습니다 . 여기에서 사용할 양식을 결정할 수 있습니다.

과거에는에서 인스턴스 변수를 지정하는 것을 선호 @implementation {}했지만 이제는 @synthesize중복 유형을 제거하고 백업 변수를 속성에 명시 적으로 연결하므로 경로가 더 나은 선택 이라고 생각 합니다.

  1. 속성의 유형을 변경하면 인스턴스 변수의 유형이 변경됩니다.
  2. 저장소 한정자를 변경하면 (예 : 강함 대신 약하게 또는 약함 대신 강하게) 저장소 한정자가 변경됩니다.
  3. 속성을 제거하거나 이름을 바꾸면 @synthesize컴파일러 오류가 생성됩니다. 길잃은 인스턴스 변수로 끝나지 않을 것입니다.

*-여러 파일의 범주간에 기능을 분할하는 것과 관련하여 필요한 경우 한 가지를 알고 있습니다. 그리고 애플이 이것을 고치거나 이미 수정했다고해도 놀라지 않을 것입니다.


답변

좋아요, 속성을 만들 때 …

@property NSString *name;

Xcode는 당신이 쓴 것처럼 iVar를 자동 합성합니다.

@synthesize name = _name;

이것은 당신이 재산에 접근 할 수 있음을 의미합니다 …

self.name;
// or
_name;

둘 다 작동하지만 self.name실제로는 접근 자 메서드 만 사용합니다.

자동 합성이 작동하지 않는 경우 는 한 번뿐입니다. 덮어 쓰고 setter 및 getter 메서드를 사용하면 iVar를 합성해야합니다.

setter 만 무시하거나 getter 만 무시해도 괜찮습니다. 그러나 두 가지를 모두 수행하면 컴파일러가이를 이해하지 못하므로 수동으로 합성해야합니다.

그래도 경험상.

iVars를 만들지 마십시오. 속성을 사용하십시오. 그것을 종합하지 마십시오.


답변

프로토콜에서 속성을 선언 할 때 속성 합성이 필요합니다. 구현 인터페이스에서 자동으로 합성되지 않습니다.


답변

명확히 해주셔서 감사합니다. 비슷한 문제가있었습니다.

@synthesize firstAsset, secondAsset, audioAsset;
@synthesize activityView;

그래서 이제 그것들을 주석 처리 한 후, 나는 각 사건을 예를 들어

self.firstAsset firstAsset도 사용할 수있는 것 같지만 “이 (가) 너무 자주 표시되지 않습니다.


답변

Xcode는 명시적인 @synthesize선언이 필요하지 않습니다 .

@synthesize다음과 같이 작성하지 않으면 다음 을 수행하십시오.

@synthesize manager = _manager;

샘플 코드가 오래되었을 수 있습니다. 곧 업데이트됩니다.

다음과 같은 속성에 액세스 할 수 있습니다.

[self.manager function];

이것은 Apple에서 권장하는 규칙입니다. 나는 그것을 따르고 당신도 그렇게 할 것을 권장합니다!