programing

id 대신 instancetype을 사용하는 것이 좋을까요?

subpage 2023. 4. 19. 23:03
반응형

id 대신 instancetype을 사용하는 것이 좋을까요?

Clang이 키워드를 추가했는데, 제가 보기엔id의 반환형으로서-alloc그리고.init.

를 사용하면 어떤 이점이 있습니까?instancetype대신id?

네, 사용 시 장점이 있습니다.instancetype모든 경우에 해당됩니다.좀 더 자세히 설명하겠습니다만, 우선 다음과 같은 굵은 문장으로 시작하겠습니다.사용하다instancetype적절한 경우, 즉 클래스가 같은 클래스의 인스턴스를 반환할 때마다.

사실, 애플은 이 주제에 대해 다음과 같이 말하고 있다.

코드에서 다음 항목을 바꿉니다.id에 대한 보답으로instancetype필요한 경우.이것은 보통 의 경우입니다.init메서드 및 클래스 팩토리 메서드.컴파일러가 자동으로 "alloc", "init" 또는 "new"로 시작하는 메서드를 변환하고 반환 유형을 갖는 경우에도id돌아오다instancetype, 다른 메서드는 변환되지 않습니다.목적-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가지 장점이 있습니다.

  1. 명시적당신의 코드는 다른 무언가가 아니라 명령대로 행동하고 있습니다.
  2. 패턴.중요한 시기에 좋은 습관을 들이고 있는 거야. 실제로 존재하는 거지.
  3. 일관성.코드의 일관성이 확립되어 있기 때문에, 보다 읽기 쉬워집니다.

명시적

반품해도 기술적인 이득이 없는 것은 사실입니다.instancetype에서init이것은 컴파일러가 자동으로 변환하기 때문입니다.id로로 합니다.instancetype이 기호에 의지하고 .initid는 이 명령어를 하고 있습니다.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는 그 합니다.initmethod는 "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

반응형