'선언되지 않은 선택기'경고를 제거하는 방법


162

구현 된 프로토콜 없이 NSObject 인스턴스에서 선택기를 사용하고 싶습니다 . 예를 들어, 호출 된 NSObject 인스턴스가 지원하는 경우 오류 속성을 설정해야하는 범주 메서드가 있습니다. 이것은 코드이며 코드는 의도 한대로 작동합니다.

if ([self respondsToSelector:@selector(setError:)])
{
    [self performSelector:@selector(setError:) withObject:[NSError errorWithDomain:@"SomeDomain" code:1 userInfo:nil]];
}

그러나 컴파일러는 setError : 시그니처와 관련된 메소드를 찾지 못하므로 @selector(setError:)스 니펫 이 포함 된 각 줄에 대해 경고를 표시합니다 .

Undeclared selector 'setError:'

이 경고를 없애기 위해 프로토콜을 선언하고 싶지는 않습니다. 왜냐하면 이것을 사용하여 특별한 것을 구현하기 위해 모든 클래스를 원하지 않기 때문입니다. 관습에 따라 setError:메소드 또는 속성 을 갖기를 원합니다 .

이것이 가능합니까? 어떻게?

건배,
EP



더 이상 사용되지 않는 선택기가 경고를 발생시킵니다. 선택기가 언젠가 제거 될 수 있으므로 선택기에 더 이상 액세스하는 것이 안전하지 않습니다.
DawnSong

답변:


254

다른 옵션은 다음을 사용하여 경고를 비활성화하는 것입니다.

#pragma GCC diagnostic ignored "-Wundeclared-selector"

이 줄은 경고가 발생하는 .m 파일에 배치 할 수 있습니다.

최신 정보:

다음과 같이 LLVM에서도 작동합니다.

#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wundeclared-selector"

... your code here ...

#pragma clang diagnostic pop

#pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" // Do your thing #pragma clang diagnostic pop
dizy

예, @dizy 상태로 수행됩니다. (늦은 답변에 대해 죄송하지만 알림을 놓쳤습니다).
Klaas

나도 필요했다#pragma clang diagnostic ignored "-Wselector"
최대

1
@mdorseif 대부분 '제외해야하는'경고는 컴파일 로그에 나열됩니다. 이 개념으로 모든 경고를 음소거 할 수 있습니다. 선택기와 관련하여 귀하를 추가하게되어 기쁩니다.
Klaas

@epologee 빌드 설정 "Undeclared Selector"를 통해 동일한 작업을 수행 할 수 있습니다

194

NSSelectorFromString을 살펴 보십시오 .

 SEL selector = NSSelectorFromString(@"setError:");
 if ([self respondsToSelector:selector])

@selector키워드를 통해 컴파일 타임 대신 런타임에 선택기를 작성할 수 있으며 컴파일러는 불평 할 기회가 없습니다.


안녕하세요 @sergio, 귀하와 @jacobrelkin의 답변이 모두 효과가 있습니다. 거의 동시에 제출되었습니다. '더 나은'답변이 있으면 선택하도록 도와 주겠습니까?
epologee 2018 년

2
이 답변이 더 "코코아"-y (?)처럼 보이기 때문에이 답변이 더 좋습니다. sel_registerName()꼬추 보이는 모호하고 직접 호출하지 말아야 종류는 당신이 좀 obj_msg_send ()처럼, 무슨 일을하는지 모르는 경우)
니콜라스 미아리

15
확실하지가 엑스 코드 5,하지만이 구현 다른 경고를 받고 있어요 경우 : "셀렉터 알 수 없기 때문에 PerformSelector는 누수가 발생할 수 있습니다" .
Hampden12311

1
@ Hampden123 : 그것은 다른 문제입니다. 여기 봐 : stackoverflow.com/questions/7017281/...
세르지오

52

나는 이것이 이상한 이유로 선택기가 런타임에 등록되지 않았기 때문이라고 생각합니다.

다음을 통해 선택기를 등록하십시오 sel_registerName().

SEL setErrorSelector = sel_registerName("setError:");

if([self respondsToSelector:setErrorSelector]) {
   [self performSelector:setErrorSelector withObject:[NSError errorWithDomain:@"SomeDomain" code:1 userInfo:nil]];
}

안녕하세요 @jacobrelkin, 귀하와 @sergio의 답변이 모두 효과가 있습니다. 거의 동시에 제출되었습니다. '더 나은'답변이 있으면 선택하도록 도와 주겠습니까?
epologee 2018 년

2
@epologee NSSelectorFromStringsel_registerName()어쨌든 후드 아래에서 호출 합니다. 더 적합한 것을 선택하십시오.
Jacob Relkin

1
@epologee sel_registerName()직접 전화 하는 것이 왜하고 있는지에 대해 더 분명 하다고 생각 합니다. NSSelectorFromString하지 않는 이야기 가 선택기를 등록하려고거야 당신을.
Jacob Relkin 2018 년

8
확실하지가 엑스 코드 5,하지만이 구현 다른 경고를 받고 있어요 경우 : "셀렉터 알 수 없기 때문에 PerformSelector는 누수가 발생할 수 있습니다" .
Hampden12311

@ Max_Power89 아니요. 아래의 다른 의견을 참조하십시오. 나는 이것에 너무 많은 시간을 보내고 싶지 않아서 헤더 파일을 포함시켰다.
Hampden123

7

메소드를 사용하여 파일을 #include '하여 메시지를 제거했습니다. 그 파일에서 다른 것은 사용되지 않았습니다.


이것은 덜 우아한 해결책이지만 선택자를 받고있는 "알려진 용의자"가 있으므로 나에게 효과적입니다. 또한 런타임 선택기 접근 방식을 구현하면 performSelector 문에서 여전히 다른 경고가 표시됩니다. 즉, "Selector를 알 수 없기 때문에 PerformanceSelector에서 누수가 발생할 수 있습니다 . " 감사합니다!
Hampden12311

2
최고 투표 답변 중 어느 것도 맞지 않습니다. "선언되지 않은 선택기"경고의 목적은 의존하는 선택기의 이름을 변경하면 컴파일 타임에 오류를 포착하는 것입니다. 따라서 의존하는 메서드를 선언하는 파일을 #import로 가져 오는 것이 가장 정확합니다.
Brane

7

이 스레드에 약간 늦었다는 것을 알고 있지만 완전성을 위해 대상 빌드 설정을 사용 하여이 경고를 전체적으로 끌 수 있습니다.

'Apple LLVM 경고-Objective-C'섹션에서 다음을 변경하십시오.

Undeclared Selector - NO

6

클래스가 setError : 메소드를 구현하는 경우 (최종 오류 특성의 setter를 동적으로 선언하여도) 인터페이스 파일 (.h)에 선언하거나이를 표시하지 않으려는 경우 PrivateMethods 까다로운 트릭으로 시도하십시오.

@interface Yourclass (PrivateMethods)

- (void) yourMethod1;
- (void) yourMethod2;

@end

@implementation 직전에 경고가 숨겨져 있어야합니다.;).


고맙지 만 범주에서 메서드를 호출하므로 적용되지 않습니다. 건배, EP.
epologee 2016 년

그리고 우리 중 일부는 더 이국적인 일을하고 있습니다-선택기는 F # 객체로 구현됩니다.
James Moore

1
이것은 내가 볼 수있는, 엑스 코드 7.1.1 / 아이폰 OS 9.1에 경고를 제거하지 않습니다PerformSelector may cause a leak because its selector is unknown
loretoparisi

3

당신 .pch이나 Common.h당신이 원하는 곳에 넣을 수있는 정말 편안한 매크로 :

#define SUPPRESS_UNDECLARED_SELECTOR_LEAK_WARNING(code)                        \
_Pragma("clang diagnostic push")                                        \
_Pragma("clang diagnostic ignored \"-Wundeclared-selector"\"")     \
code;                                                                   \
_Pragma("clang diagnostic pop")                                         \

비슷한 문제에 대한 이 질문 의 편집입니다 ...


3

스크린 샷과 같이 Xcode에서 끌 수 있습니다.

여기에 이미지 설명을 입력하십시오


좋은데 아직도, 나는 "이 경우 clang이 잘못되었습니다. 입력 해 주셔서 감사합니다!
epologee

2

경고를 피하기 위해 문제의 객체를 먼저 ID로 캐스트 할 수도 있습니다.

if ([object respondsToSelector:@selector(myMethod)]) {
    [(id)object myMethod];
}

1
이것은 오늘날까지 XC7.1까지 if 표현식 내용에 대해 동일한 경고를 제거하지 않습니다.
Martin-Gilles Lavoie

2

이 경고를 피하는 또 다른 방법은 선택기 방법이 다음과 같은지 확인하는 것입니다.

-(void) myMethod :(id) sender{
}

발신자를 수락하거나 원하는 경우 발신자 객체의 유형을 지정하려면 "(id) 발신자"를 잊지 마십시오.


0

정답은 가져 오기를 통해 Xcode에 알리거나 이러한 선택기가 존재하는 선택기를 등록하는 데있을 수 있지만 필자의 경우 세미콜론이 누락되었습니다. 오류를 "수정"하기 전에 오류가 정확하고 코드가 올바르지 않은지 확인하십시오. 예를 들어 Apple의 MVCNetworking 샘플에서 오류를 발견했습니다.


아니요, 정답은 가져 오기를 통해 Xcode에 알리지 못했습니다. 정답은 @sergio의 답변도 문제를 해결할 수 있지만 위의 답변은 ... 정답입니다. 잘못된 선택기를 사용하는 것은 이 질문의 주제가 아니므로 선택기를 변경하는 것은 답이 아닙니다. 난 당신에게 downvote을 저장합니다.
epologee

1
의견을 써야했을 것입니다. 내가 말할 수있는 것은 가져 오기가 누락되면이 특정 인스턴스가 아니라면이 Xcode 경고가 발생한다는 것입니다. 런타임에 선택기를 작성하거나 동적 방식 (예 : methodSignatureForSelector)으로 메소드 호출에 응답 할 때 NSSelectorFromString 또는 기타 "등록"옵션 만 권장합니다. 등록하면 "오류를 해결하는 중"이라는 의미이므로 일부 상황에서는 맞지 않습니다. 더 정확한 접근 방식은 경고를 수정하는 것입니다 (클랑 분석이 정확하다면).
Louis St-Amour

사실, 나는 원래의 질문에 "구현 된 프로토콜이 필요하지 않다"고 명확하게 언급하고 있으며 수입에 대해서는 언급하지 않았다. 따라서 범주 자체를 가져 오는 것이이 사용자에게 가장 적합한 옵션 일 수 있습니다. 여기 다른 어떤 것도 기술적으로 말해서 선택기를 두 번 정의 할 수 있습니다. 예? -편집 : 아, 나는 이것을 너무 멀리 가져 갔다. 답변 해 주셔서 감사합니다. 이제 그만하겠습니다. :)
Louis St-Amour

-1

나는 아무것도 방법을 추가하여 경고를 사라지게 할 수있었습니다 (공개 : 나는 이것을 생각하지 않았지만 scheduled timerwithtimeinterval에서 인터넷 검색하여 찾았습니다)

    [NSTimer scheduledTimerWithTimeInterval:[[NSDate distantFuture] timeIntervalSinceNow]
                                     target:self
                                   selector:@selector(donothingatall:)
                                   userInfo:nil
                                    repeats:YES];


    [[NSRunLoop currentRunLoop] run];

    HTTPLogVerbose(@"%@: BonjourThread: Aborted", THIS_FILE);

    }
}

+ (void) donothingatall:(NSTimer *)timer
{

}

경고를 숨기는 방법을 아는 것에 대해 감사하지만 경고를 수정하는 것이 더 좋으며 Sergio와 Relkin의 기술은 알 수없는 이유로 저에게 효과적이지 않았습니다.


1
다른 사람이 솔루션, 읽는 경우 작동 , 그가를 / 그녀는 꽤 미래의 자기를 포함하여 혼동 될 것이다. 존재하지 않는 선택기를 호출하여 경고를 발생 시켜서 수행중인 작업을 알고 있다면 오해의 소지가있는 스텁을 건너 뛰고 코드가 의도를 표현하도록하십시오.
epologee

1
좋은 지적. 상속 된 코드로 작업하고 경고가 사라지는 방법을 알아 내려고 왜 존재하지 않는 선택기가 있는지에 대한 기본적인 질문을 해결하려고하지 않았습니다. 한 번에 한 걸음 씩 항상 말합니다.
user938797
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.