짧은 답변 :
- 당신은
NSObject
클래스, 또는 NSObject
에서 상속하는 모든 클래스에 어떤 NSObject
인스턴스 메소드 (예 : respondsToSelector:
또는 init
)를 보낼 수 있습니다.
[NSObject init]
은 CoreFoundation에서 재정의되고 런타임 예외가 발생합니다 ( OS X 10.6 이상에서 연결된 바이너리).
긴 답변 :
이의 당신의 마지막 질문부터 시작하자 : respondsToSelector
이후 또한
는, 인스턴스 방법입니다, 왜 먼저 그것을 호출 할 수도있다?
respondsToSelector:
는 NSObject
클래스에 따르는 것으로 NSObject
프로토콜 인스턴스 메소드이다. 이제 NSObject
클래스 (및 각 하위 클래스) 은 루트 클래스 NSObject
의 하위 클래스 인스턴스와 객체입니다.
이 설명 그렉 파커 문서 [objc explain]: Classes and metaclasses (강조 첨가)에 도시되어
더 중요한 메타 클래스의 슈퍼 클래스이다. 메타 클래스의 수퍼 클래스 체인은 클래스의 수퍼 클래스 체인 과 유사하므로 클래스 메소드는 인스턴스 메소드와 병렬로 상속됩니다. 루트 Metaclass의 수퍼 클래스가 루트 클래스 인 이므로 각 클래스 개체가 루트 클래스의 인스턴스 메서드에 응답합니다. 결국 클래스 개체는 다른 개체와 마찬가지로 루트 클래스의 하위 클래스의 인스턴스입니다.
이렇게하면 respondsToSelector:
을 NSObject
클래스로 보낼 수있는 이유가 설명됩니다. 주어진 selector가있는 클래스 메서드가 있으면 반환 값은 YES
입니다.
NSString *path = [NSString performSelector:@selector(pathWithComponents:) withObject:@[@"foo", @"bar"]];
performSelector:withObject:
는 인스턴스 메소드 NSObject
의, 당신은 NSString
클래스이 메시지를 보낼 수 있습니다 : 여기
는 또 다른 예이다. 이 경우, 결과는
NSString *path = [NSString pathWithComponents:@[@"foo", @"bar"];
최초의 질문에 이제
과 동일합니다 :
왜 "초기화하기"를 선택하여 NSObject의에 respondsToSelector
를 실행 않아도 실행하지만 1 을 반환 [NSObject init]
에 런타임 오류가 발생합니까? 위와 같은 추론
NSObject
에서 파생되는 모든 클래스에
init
메시지를 송신 할 수 있어야한다.
// Replaced by CF (throws an NSException)
+ (id)init {
return (id)self;
}
이 왜
[NSObject respondsToSelector:@selector(init)] == YES
NSObject의의 의견을 설명합니다
지금 NSObject
는 런타임에 예외를 던져 문서화 된 클래스 메소드 init
, 이 http://opensource.apple.com/source/objc4/objc4-532.2/runtime/NSObject.mm 볼 수있다 .mm은 CoreFoundation에서 +init
이 대체되고 실제로는이라고 명시합니다. 예외가 발생 될 때는 스택 백 트레이스는
(lldb) bt
* thread #1: tid = 0x6eda, 0x01f69952 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
....
frame #8: 0x0156b9fc libobjc.A.dylib`objc_exception_throw + 323
frame #9: 0x01889931 CoreFoundation`+[NSObject(NSObject) init] + 241
* frame #10: 0x00002a51 foo`main(argc=1, argv=0xbfffee30) + 257 at main.m:25
그래서이 방법 CoreFoundation에서 예외에 대한 책임이있다.
내가 모르는 init
방법은 CoreFoundation에서 (대신 NSObject
에서 직접 예외를 throw)에서 재정의되고 대체 방법은 오픈 소스 저장소의 일부가 될 수없는 것 같습니다 이유http://opensource.apple.com/source/CF/CF-855.14/ (적어도 나는 그것을 거기에서 발견 할 수 없었다).
하지만 흥미로운 점은 OS 릴리스간에 관찰 된 동작이 변경되었을 수 있습니다.OS X 10.5에 컴파일
id x = [NSObject init];
경우, 그것은 작동하고 NSObject
클래스 객체를 반환합니다. 바이너리가 OS X 10.5에서 컴파일되고 링크되어 있고 같은 OS X 10.9와 같은 최신 릴리스에서 실행되는 경우에도 작동합니다. 이
또한 바이너리 OS X 10.6 이상에 연결되어있는 경우 (http://www.opensource.apple.com/source/CF/CF-476.14/CFPriv.h부터) CoreFoundation`+[NSObject(NSObject) init]:
0x1019d8ad0: pushq %rbp
0x1019d8ad1: movq %rsp, %rbp
0x1019d8ad4: pushq %rbx
0x1019d8ad5: pushq %rax
0x1019d8ad6: movq %rdi, %rbx
0x1019d8ad9: movl $0x6, %edi
0x1019d8ade: callq 0x1018dfcc0 ; _CFExecutableLinkedOnOrAfter
0x1019d8ae3: testb %al, %al
0x1019d8ae5: jne 0x1019d8af1 ; +[NSObject(NSObject) init] + 33
0x1019d8ae7: movq %rbx, %rax
0x1019d8aea: addq $0x8, %rsp
0x1019d8aee: popq %rbx
0x1019d8aef: popq %rbp
0x1019d8af0: ret
0x1019d8af1: movq %rbx, %rdi
0x1019d8af4: callq 0x101a19cee ; symbol stub for: class_getName
0x1019d8af9: leaq 0x9fe80(%rip), %rcx ; kCFAllocatorSystemDefault
0x1019d8b00: movq (%rcx), %rdi
0x1019d8b03: leaq 0xc5a66(%rip), %rdx ; @"*** +[%s<%p> init]: cannot init a class object."
...
0x1019d8b72: callq *0x9e658(%rip) ; (void *)0x00000001016b9fc0: objc_msgSend
0x1019d8b78: movq %rax, %rdi
0x1019d8b7b: callq 0x101a19d4e ; symbol stub for: objc_exception_throw
_CFExecutableLinkedOnOrAfter()
의 어셈블리 코드에서 수표 보았다, 그 경우 예외 이 발생 될 수있다.
따라서 이전 OS 릴리스에서는 클래스 객체에서 init
을 호출해야합니다. 따라서 과 CoreFoundation은 이전 버전과의 호환성을 위해 "이전 바이너리"에서 허용합니다.
아주 좋은 답변입니다! –