해결책
컴파일러는 이에 대해 경고하고 있습니다. 이 경고를 무시해야하는 경우는 매우 드물며 해결하기 쉽습니다. 방법은 다음과 같습니다.
if (!_controller) { return; }
SEL selector = NSSelectorFromString(@"someMethod");
IMP imp = [_controller methodForSelector:selector];
void (*func)(id, SEL) = (void *)imp;
func(_controller, selector);
또는 더 끔찍하게 (가드없이 읽기가 어렵지만) :
SEL selector = NSSelectorFromString(@"someMethod");
((void (*)(id, SEL))[_controller methodForSelector:selector])(_controller, selector);
설명
여기서 진행중인 것은 컨트롤러에 해당하는 메소드에 대한 C 함수 포인터를 컨트롤러에 요청하는 것입니다. 모든 NSObject
응답에 응답 methodForSelector:
하지만 class_getMethodImplementation
Objective-C 런타임 에서도 사용할 수 있습니다 (와 같은 프로토콜 참조 만있는 경우 유용 id<SomeProto>
). 이 함수 포인터를 IMP
s 라고 하며 간단한 typedef
함수 포인터 ( id (*IMP)(id, SEL, ...)
) 1 입니다. 이것은 메소드의 실제 메소드 서명에 가깝지만 항상 정확하게 일치하지는 않습니다.
를 가지고 나면 IMP
ARC에 필요한 모든 세부 사항 (두 개의 암시 적 숨겨진 인수 self
및 _cmd
모든 Objective-C 메서드 호출 포함) 이 포함 된 함수 포인터로 캐스트해야합니다 . 이것은 세 번째 줄에서 처리됩니다 ( (void *)
오른쪽에있는 포인터는 포인터 유형이 일치하지 않으므로 수행중인 작업을 알고 경고를 생성하지 않음을 컴파일러에게 알려줍니다).
마지막으로 함수 포인터 2 를 호출합니다 .
복잡한 예
선택자가 인수를 받거나 값을 반환하면 약간 변경해야합니다.
SEL selector = NSSelectorFromString(@"processRegion:ofView:");
IMP imp = [_controller methodForSelector:selector];
CGRect (*func)(id, SEL, CGRect, UIView *) = (void *)imp;
CGRect result = _controller ?
func(_controller, selector, someRect, someView) : CGRectZero;
경고에 대한 추론
이 경고의 이유는 ARC를 사용하면 런타임에서 호출하는 메소드의 결과로 수행 할 작업을 알아야하기 때문입니다. 그 결과는 무엇이든 될 수있다 : void
, int
, char
, NSString *
, id
, 등 ARC는 일반적으로 작업중인 개체 형식의 헤더에서이 정보를 가져옵니다. 삼
ARC는 반환 값을 고려할 것이라고에만 4 일이 정말있다 : 4
- 무시가 아닌 개체 유형 (
void
, int
, 등)
- 객체 값을 유지 한 다음 더 이상 사용하지 않을 때 해제합니다 (표준 가정)
- 더 이상 사용하지 않을 때 새 객체 값을 해제합니다 (
init
/ copy
패밀리의 메소드 또는 로 표시된 메소드 ns_returns_retained
).
- 아무것도 수행하지 않고 반환 된 객체 값이 로컬 범위에서 유효하다고 가정합니다 (가장 큰 릴리스 풀이 배수 될 때까지
ns_returns_autoreleased
)
에 대한 호출은 methodForSelector:
이 부르고 메소드의 반환 값이 대상이지만, 해제 / 유지하지 않는 것으로 가정합니다. 따라서 위의 # 3에서와 같이 객체가 해제되어야하는 경우 누출을 일으킬 수 있습니다 (즉, 호출하는 메소드가 새 객체를 반환합니다).
해당 반환 void
또는 다른 객체 이외의 객체 를 호출하려는 선택기의 경우 컴파일러 기능을 사용하여 경고를 무시할 수는 있지만 위험 할 수 있습니다. Clang이 로컬 변수에 할당되지 않은 반환 값을 처리하는 방법에 대한 몇 가지 반복을 살펴 보았습니다. ARC가 활성화되어 methodForSelector:
있어도 사용하지 않으려 는 경우에도 반환 된 객체 값을 유지 및 해제 할 수없는 이유 는 없습니다. 컴파일러의 관점에서 볼 때 결국 객체입니다. 즉, 호출하는 메소드가 someMethod
객체를 포함하여 비 객체를 반환 void
하면 가비지 포인터 값이 유지 / 해제되고 충돌 할 수 있습니다.
추가 인수
한 가지 고려 사항은 이것이 동일한 경고와 함께 발생하며 performSelector:withObject:
해당 메소드가 매개 변수를 사용하는 방법을 선언하지 않으면 비슷한 문제 가 발생할 수 있다는 것입니다. ARC를 사용하면 소비 된 매개 변수 를 선언 할 수 있으며 메서드가 매개 변수를 사용하는 경우 결국 좀비에게 메시지를 보내 충돌이 발생할 수 있습니다. 브리지 캐스팅으로이 문제를 해결할 수있는 방법이 있지만 실제로 IMP
위 의 and 함수 포인터 방법을 사용하는 것이 좋습니다 . 소비되는 매개 변수는 거의 문제가되지 않으므로이 문제는 발생하지 않습니다.
정적 선택기
흥미롭게도 컴파일러는 정적으로 선언 된 선택기에 대해 불평하지 않습니다.
[_controller performSelector:@selector(someMethod)];
그 이유는 컴파일러가 실제로 컴파일하는 동안 선택기와 객체에 대한 모든 정보를 기록 할 수 있기 때문입니다. 아무것도 추측 할 필요가 없습니다. (저는 1 년 전에 출처를 확인하여 확인했지만 지금은 참조 자료가 없습니다.)
억압
이 경고의 억제가 필요한 상황과 코드 디자인이 좋은 상황을 생각할 때 나는 비어 있습니다. 누군가이 경고음이 필요했던 경험이 있다면 공유하십시오. (위의 내용이 제대로 처리되지 않습니다.)
더
NSMethodInvocation
이것을 처리 하기 위해를 구축하는 것도 가능 하지만 그렇게하려면 더 많은 타이핑이 필요하고 느리기 때문에 그렇게 할 이유가 거의 없습니다.
역사
performSelector:
메소드 계열이 처음 Objective-C에 추가 되었을 때 ARC는 존재하지 않았습니다. ARC를 작성하는 동안 Apple은 개발자가 명명 된 선택기를 통해 임의의 메시지를 보낼 때 메모리를 처리하는 방법을 명시 적으로 정의하는 다른 방법을 사용하도록 안내하는 방법으로 이러한 방법에 대해 경고를 생성하기로 결정했습니다. Objective-C에서 개발자는 원시 함수 포인터에서 C 스타일 캐스트를 사용하여이를 수행 할 수 있습니다.
Swift가 도입되면서 Apple 은performSelector:
여러 가지 방법을 "본질적으로 안전하지 않은"것으로 문서화 했으며 Swift에서는 사용할 수 없습니다.
시간이 지남에 따라 우리는 이러한 진행을 보았습니다.
- 초기 버전의 Objective-C 허용
performSelector:
(수동 메모리 관리)
- ARC가있는 Objective-C는 다음을 사용하도록 경고합니다.
performSelector:
- Swift는
performSelector:
이러한 방법을 "본질적으로 안전하지 않은" 것으로 접근 및 문서화 할 수 없습니다.
그러나 명명 된 선택기를 기반으로 메시지를 전송한다는 아이디어는 "본질적으로 안전하지 않은"기능이 아닙니다. 이 아이디어는 Objective-C와 다른 많은 프로그래밍 언어에서 오랫동안 성공적으로 사용되었습니다.
1 모든 목표 - C 방법은 두 가지 숨겨진 인수를, self
그리고 _cmd
당신이 메서드를 호출 할 때 그 암시 적으로 추가됩니다.
2NULL
C에서 함수 호출 은 안전하지 않습니다. 컨트롤러가 있는지 확인하는 데 사용되는 가드는 우리에게 물체가 있는지 확인합니다. 따라서 우리는 우리가 얻을 것이다 알고 IMP
에서 methodForSelector:
(이있을 수 있지만 _objc_msgForward
, 메시지 전달 시스템에 입력)를. 기본적으로 경비원을 배치하면 전화를 걸 수있는 기능이 있다는 것을 알고 있습니다.
3 실제로 객체를 선언 id
하고 모든 헤더를 가져 오지 않으면 잘못된 정보를 얻을 수 있습니다. 컴파일러가 생각하는 코드 충돌이 발생할 수 있습니다. 이것은 매우 드물지만 발생할 수 있습니다. 일반적으로 두 가지 메소드 서명 중 어느 것을 선택할지 모른다는 경고가 나타납니다.
4 자세한 내용은 유지 반환 값 및 유지 되지 않은 반환 값에 대한 ARC 참조 를 참조하십시오.