id 대신 instancetype을 사용하는 것이 좋을까요?
Clang이 키워드를 추가했는데, 제가 보기엔id
의 반환형으로서-alloc
그리고.init
.
를 사용하면 어떤 이점이 있습니까?instancetype
대신id
?
네, 사용 시 장점이 있습니다.instancetype
모든 경우에 해당됩니다.좀 더 자세히 설명하겠습니다만, 우선 다음과 같은 굵은 문장으로 시작하겠습니다.사용하다instancetype
적절한 경우, 즉 클래스가 같은 클래스의 인스턴스를 반환할 때마다.
사실, 애플은 이 주제에 대해 다음과 같이 말하고 있다.
코드에서 다음 항목을 바꿉니다.
id
에 대한 보답으로instancetype
필요한 경우.이것은 보통 의 경우입니다.init
메서드 및 클래스 팩토리 메서드.컴파일러가 자동으로 "alloc", "init" 또는 "new"로 시작하는 메서드를 변환하고 반환 유형을 갖는 경우에도id
돌아오다instancetype
, 다른 메서드는 변환되지 않습니다.목적-C 규약은 모든 방법에 대해 명시적으로 기술하는 것입니다.
- 강조해 주세요.출처:현대적 목적의 도입-C
이제 그만하고 왜 좋은 생각인지 설명해보도록 하겠습니다.
먼저, 몇 가지 정의를 제시하겠습니다.
@interface Foo:NSObject
- (id)initWithBar:(NSInteger)bar; // initializer
+ (id)fooWithBar:(NSInteger)bar; // class factory
@end
클래스 팩토리의 경우 항상 다음을 사용해야 합니다.instancetype
컴파일러는 자동으로 변환되지 않습니다.id
로.instancetype
.그거id
는 범용 객체입니다.하지만 만약 당신이 그것을instancetype
컴파일러는 메서드가 반환하는 오브젝트의 유형을 알고 있습니다.
이것은 학문적인 문제가 아니다.예를 들어.[[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData]
Mac OS X에서 오류가 발생합니다(만). 결과, 파라미터 유형 또는 속성이 일치하지 않는 'writeData:'라는 이름의 여러 메서드가 발견되었습니다.그 이유는 NSFileHandle과 NSURLHandle이 둘 다writeData:
.부터[NSFileHandle fileHandleWithStandardOutput]
반환하다id
컴파일러는 어떤 클래스인지 알 수 없습니다.writeData:
가 호출되고 있습니다.
다음 중 하나를 사용하여 이 문제를 해결해야 합니다.
[(NSFileHandle *)[NSFileHandle fileHandleWithStandardOutput] writeData:formattedData];
또는 다음과 같이 입력합니다.
NSFileHandle *fileHandle = [NSFileHandle fileHandleWithStandardOutput];
[fileHandle writeData:formattedData];
물론, 더 나은 해결책은 선언하는 것이다.fileHandleWithStandardOutput
의 반환으로서instancetype
그럼 배역이나 과제가 필요없겠네요.
(iOS에서는, 이 예에서는, 다음의 에러만을 발생시키지 않습니다.NSFileHandle
를 제공하다writeData:
다른 예들이 존재합니다. 예를 들어,length
이 경우 a가 반환됩니다.CGFloat
부터UILayoutSupport
단,NSUInteger
부터NSString
.)
메모: 이 글을 쓴 이후 macOS 헤더가 수정되어 반환되었습니다.NSFileHandle
대신id
.
이니셜라이저의 경우 더 복잡합니다.다음을 입력할 때:
- (id)initWithBar:(NSInteger)bar
...컴파일러는 사용자가 입력한 것으로 간주합니다.
- (instancetype)initWithBar:(NSInteger)bar
이것은 ARC에 필요했습니다.이는 Clang Language Extensions 관련 결과 유형에 설명되어 있습니다.이것이 사람들이 당신에게 사용할 필요가 없다고 말하는 이유입니다.instancetype
그래야 할 것 같지만요이 답변의 나머지 부분은 이 문제를 다루고 있습니다.
3가지 장점이 있습니다.
- 명시적당신의 코드는 다른 무언가가 아니라 명령대로 행동하고 있습니다.
- 패턴.중요한 시기에 좋은 습관을 들이고 있는 거야. 실제로 존재하는 거지.
- 일관성.코드의 일관성이 확립되어 있기 때문에, 보다 읽기 쉬워집니다.
명시적
반품해도 기술적인 이득이 없는 것은 사실입니다.instancetype
에서init
이것은 컴파일러가 자동으로 변환하기 때문입니다.id
로로 합니다.instancetype
이 기호에 의지하고 .init
id
는 이 명령어를 하고 있습니다.instancetype
.
이것들은 컴파일러와 동등합니다.
- (id)initWithBar:(NSInteger)bar;
- (instancetype)initWithBar:(NSInteger)bar;
이것들은 당신의 눈과 같지 않습니다.기껏해야 차이를 무시하고 대충 넘기는 법을 배우게 될 것이다.이건 무시하는 법을 배울 일이 아니야.
양식
★★★★★★★★★★★★★★★★★★★★★와 차이는 없지만init
클래스 팩토리를 정의하는 즉시 다른 방법이 있습니다.
이 두 가지는 동일하지 않습니다.
+ (id)fooWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
입력에 instancetype
컨스트럭터의 리턴 타입으로서 매번 올바르게 동작합니다.
일관성.
하면, 「 것은 」, 「원하는 것은 없다」, 「원하는 것은 없다」라고 생각해 주세요.init
★★★★★★★★★★★★★★★★★★★★★★★★★★★
「 」를 사용하고 id
★★★★★★에init
하다
- (id)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
,을 instancetype
뭇매를 맞다
- (instancetype)initWithBar:(NSInteger)bar;
+ (instancetype)fooWithBar:(NSInteger)bar;
더 일관되고 읽기 쉬워요.똑같은 걸 돌려줬는데 이제 알겠네요
결론
컴파일러의 , 「」를 사용해 .instancetype
적절한 경우.
글을 합니다.id
이 클래스의 입니까?이것은 이 클래스의 인스턴스를 반환하는 것입니까?만약 그렇다면, 그것은instancetype
.
해야 할 .id
, 「」를 사용할 것입니다instancetype
훨씬 더 자주.
확실히 이득이 있다.'id'를 사용하면 기본적으로 유형 확인이 전혀 수행되지 않습니다.instancetype을 사용하면 컴파일러와 IDE는 반환되는 유형의 것을 인식하고 코드를 더 잘 체크하고 자동 완성할 수 있습니다.
id는 물론 적절한 경우에만 사용하십시오(즉, 해당 클래스의 인스턴스를 반환하는 메서드). id는 여전히 유용합니다.
위의 답변은 이 질문을 설명하기에 충분합니다.저는 독자들이 코딩에 대해 이해할 수 있도록 예를 하나 추가하고자 합니다.
클래스 A
@interface ClassA : NSObject
- (id)methodA;
- (instancetype)methodB;
@end
클래스 B
@interface ClassB : NSObject
- (id)methodX;
@end
TestViewController.m
#import "ClassA.h"
#import "ClassB.h"
- (void)viewDidLoad {
[[[[ClassA alloc] init] methodA] methodX]; //This will NOT generate a compiler warning or error because the return type for methodA is id. Eventually this will generate exception at runtime
[[[[ClassA alloc] init] methodB] methodX]; //This will generate a compiler error saying "No visible @interface ClassA declares selector methodX" because the methodB returns instanceType i.e. the type of the receiver
}
또한 Designated Initializer에서 자세한 정보를 얻을 수 있습니다.
**
인스톨 타입
** 이 키워드는 리시버의 리턴 타입과 일치하는 리턴 타입에만 사용할 수 있습니다.init 메서드는 항상 instancetype을 반환하도록 선언됩니다.예를 들어 파티 인스턴스의 반환 유형을 Party로 만들면 어떨까요?만약 Party 클래스가 하위 클래스로 분류된다면 그것은 문제를 일으킬 것이다.서브클래스는 이니셜라이저 및 반환 유형을 포함하여 Party에서 모든 메서드를 상속합니다.서브클래스의 인스턴스가 이 이니셜라이저 메시지를 보낸 경우 반환되는 것입니까?파티 인스턴스에 대한 포인터가 아니라 하위 클래스의 인스턴스에 대한 포인터입니다.문제없다고 생각할 수 있습니다.반환 타입을 변경하기 위해 서브클래스의 이니셜라이저를 덮어씁니다.그러나 Objective-C에서는 셀렉터가 같고 반환 유형(또는 인수)이 다른2개의 메서드를 사용할 수 없습니다.초기화 메서드가 "수신 객체의 인스턴스"를 반환하도록 지정하면 이 상황에서 무슨 일이 일어나는지 걱정할 필요가 없습니다.**
아이디
** instancetype이 Objective-C에 도입되기 전에 이니셜라이저는 id(eye-dee)를 반환합니다.이 유형은 "모든 개체에 대한 포인터"로 정의됩니다.(id는 C의 void *와 매우 유사합니다.)현재 XCode 클래스 템플릿에서는 보일러 플레이트코드에 추가된 이니셜라이저의 반환 타입으로 id를 사용하고 있습니다.instancetype과 달리 id는 반환 유형으로만 사용할 수 없습니다.변수가 가리키는 오브젝트 유형이 불분명한 경우 유형 ID의 변수 또는 메서드 매개 변수를 선언할 수 있습니다.고속 열거를 사용하여 여러 개체 유형 또는 알 수 없는 개체 배열에 대해 반복할 때 id를 사용할 수 있습니다.id는 "any object로의 포인터"로 정의되지 않으므로 이 유형의 변수 또는 객체 파라미터를 선언할 때 *는 포함하지 않습니다.
타입 ''' '''
instancetype
는, 「」로부터의 있습니다.init
는, 「」의과입니다.init
이치노불일치를 로 표시할 수 있도록 입니다.콘텍스트에 이 오브젝트를 입니다.이것은 컨텍스트에 근거해 반환되는 오브젝트의 클래스를 결정합니다.즉, 예를 들면,init
'메시지'에 대한 메시지alloc
.Fraction
는 그 합니다.init
method는 "instancetype이 됩니다.Fraction
in 。은 타입으로 되어 있었습니다.id
상속된 초기화 메서드는 반환되는 오브젝트 유형을 명시적으로 정의할 수 없기 때문에 서브클래싱을 고려할 때 이 새로운 타입이 더 적합합니다.
오브젝트 초기화 중, Stephen G. Kochan, Programming in Objective-C, 제6판
언급URL : https://stackoverflow.com/questions/8972221/would-it-be-beneficial-to-begin-using-instancetype-instead-of-id
'programing' 카테고리의 다른 글
각도로 컴포넌트를 새로 고치는 방법 (0) | 2023.04.24 |
---|---|
NSString을 NSDate로 변환(및 다시 되돌림) (0) | 2023.04.24 |
Windows 배치 파일: .bat vs .cmd? (0) | 2023.04.19 |
마스터 데이터베이스에 기록된 데이터베이스 소유자 SID가 데이터베이스 소유자 SID와 다릅니다. (0) | 2023.04.19 |
bash 스크립트에 타임스탬프 변수 생성 (0) | 2023.04.19 |