Objective-C에서 클래스의 인스턴스를 @protocol로 캐스트


102

내가 정의한 프로토콜을 따르거나 따르지 않을 수있는 객체 (UIViewController)가 있습니다.

객체가 프로토콜을 준수하는지 확인한 다음 안전하게 메서드를 호출 할 수 있다는 것을 알고 있습니다.

if([self.myViewController conformsToProtocol:@protocol(MyProtocol)]) {
    [self.myViewController protocolMethod]; // <-- warning here
}

그러나 XCode는 경고를 표시합니다.

warning 'UIViewController' may not respond to '-protocolMethod'

이 경고를 방지하는 올바른 방법은 무엇입니까? 내가 캐스트 수가 없어 self.myViewControllerA와 MyProtocol클래스입니다.

답변:


171

이를 수행하는 올바른 방법은 다음과 같습니다.

if ([self.myViewController conformsToProtocol:@protocol(MyProtocol)])
{
        UIViewController <MyProtocol> *vc = (UIViewController <MyProtocol> *) self.myViewController;
        [vc protocolMethod];
}

UIViewController <MyProtocol> *타입 캐스트로 변환 사용한 반면, "VC는 MyProtocol 따를이있는 개체의 UIViewController하다" id <MyProtocol>로 변환을 "VC 미지 클래스 그 MyProtocol에 부합하는 것을 목적으로한다"는.

이런 식으로 컴파일러는 적절한 유형 검사를 제공합니다 vc. 컴파일러는 둘 중 하나에서 선언되지 않은 메서드 UIViewController<MyProtocol>호출 되는 경우에만 경고를 제공합니다 . id캐스트되는 객체의 클래스 / 유형을 모르는 경우에만 사용해야합니다.


2
프로토콜을 사용할 때 실제로 객체 유형에 대해 신경 쓰지 않아야합니다. 프로토콜의 요점은 모든 객체 유형이이를 채택하고 특정 객체로 캐스트하지 않고도 사용할 수 있다는 것입니다. 따라서 위의 대신 프로토콜로 캐스팅하는 모든 곳에서 @andy의 답변을 사용하는 것이 좋습니다. id<MyProtocol> p = (id<MyProtocol>)self.myViewController;이 답변과 @andys는 모두 정확하지만 정확합니다.
memmons

2
@Answerbot 귀하의 의견이 잘못되었으며 내 답변의 마지막 단락에서 언급 한 요점을 놓칩니다. 상황에 따라 객체 유형에 관심이있을 수도 있고 관심이 없을 수도 있습니다. 어떻게 당신이 메시지에 선언 보내려면 어떻게 UIViewControllervc내 대답의 예에서, 그것은으로 선언이야 id <MyProtocol>?
Nick Forge

내 의견과 관련하여 무엇이 잘못되었는지 확실하지 않습니까? 어쨌든 객체가 프로토콜을 준수하는지 확인하는 경우 프로토콜과 관련이없는 다른 메서드를 호출하는 이유는 무엇입니까? 나는 이것을 할 필요가 있거나 내가 검토 한 코드에서 이것을 본 기억이 없습니다. 코드 냄새가 나는 것 같습니다.
memmons

당신이 그것을 보거나 사용하지 않았다고해서 그것이 코드 냄새라는 것을 의미하지는 않습니다. 다음은 사용하여 유형 정보를 버리는 id것이 문제가되는 한 가지 예를 보여주는 코드 스 니펫입니다 . gist.github.com/nsforge/7743616
Nick Forge

60

다음과 같이 전송할 수 있습니다.

if([self.myViewController conformsToProtocol:@protocol(MyProtocol)])
{
    id<MyProtocol> p = (id<MyProtocol>)self.myViewController;
    [p protocolMethod];
}

이것은 또한 나를 조금 던졌다. Objective-C에서 프로토콜은 유형 자체가 아니므 idNSObject원하는 프로토콜과 함께 지정해야합니다 (또는 다른 유형 (예 :) ).


아, 고마워요. 방금 확인한 결과 캐스팅이 (id)작동 하는 것을 보았습니다 . 그게 나쁜 형태인가요?
포드

1
id <MyProtocol>로 캐스팅하면 컴파일러는 해당 프로토콜에 정의되지 않은 메서드를 사용하는 경우 경고합니다.
dreamlax

1
@dreamlax-컴파일러가 프로토콜에 대해 유형 검사를 수행하는 방법입니다. 자세한 내용은 developer.apple.com/documentation/Cocoa/Conceptual/ObjectiveC/… 를 참조하십시오 .
Andy

1
@Ford-구체적으로 프로토콜을 사용하는 것이 더 낫습니다. 그렇게하면 컴파일러가 당신을 위해 어떤 타입 검사를 수행 할 수 있기 때문입니다.
Andy

1
@Andy, 'id'가 이미 포인터이기 때문에 '*'가 필요하지 않다고 생각합니다. 그래서 : id <MyProtocol> p = (id <MyProtocol>) self.myViewController; [p protocolMethod]; 또는 그냥 : [(id <MyProtocol>) self.myViewController protocolMethod];
포드
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.