Почему функция выполнения objc "class addMethod ()" добавляет реализацию как экземпляр и метод класса, когда целевой класс является "NSObject"?
когда я использую функцию выполнения objc class_addMethod()
чтобы внедрить реализацию в селектор экземпляра NSObject, он фактически внедряет реализацию в селектор экземпляра и селектор класса:
@implementation HelloWorldClass
- (void) helloWorld{
NSLog(@"hello world from instance method -helloWorld");
}
@end
// ====
// Do method injection when the application did finish launching.
Class sourceClass = objc_getClass("HelloWorldClass");
Class targetClass = objc_getClass("NSObject");
SEL helloWorldSelector = @selector(helloWorld);
Method method = class_getInstanceMethod(sourceClass, helloWorldSelector);
IMP imp = method_getImplementation(method);
const char *methodTypeEncoding = method_getTypeEncoding(method);
class_addMethod(targetClass, helloWorldSelector, imp, methodTypeEncoding);
теперь мы просто объявляем интерфейс helloWorld
через категорию Objc и вызовите helloWorld
сообщения NSObject
экземпляр и класс:
// Declare the interface for `helloWorld
@interface NSObject (HelloWorld)
+ (void) helloWorld;
- (void) helloWorld;
@end
// Send the `helloWorld` message to NSObject class
NSLog(@"Send the `helloWorld` message to NSObject class");
[NSObject helloWorld];
// Send the `helloWorld` message to NSObject instance
NSLog(@"Send the `helloWorld` message to NSObject instance");
[[NSObject new] helloWorld];
хотя вы только что ввели helloWorld
реализация экземпляра NSObject селектор через class_addMethod()
, но сообщения класса и экземпляра разрешаются после инъекции:
=> Send the `helloWorld` message to NSObject class
=> hello world from instance method -helloWorld
=> Send the `helloWorld` message to NSObject instance
=> hello world from instance method -helloWorld
после тестирования, я обнаружил, что class_addMethod()
добавляет реализацию к селекторам классов и экземпляров только тогда, когда целевой класс class_addMethod()
is NSObject
.
это ошибка для objc-runtime или Cocoa?
1 ответов
нет, это не ошибка. Это определенное (хотя и неясное) поведение системы выполнения.
так как каждый экземпляр имеет isa
переменная экземпляра, указывающая на класс, каждая структура класса в памяти имеет isa
член, который указывает на его метакласс. И так же, как любой данный класс содержит метаданные о своих экземплярах, включая список методов, на которые отвечают экземпляры, метакласс класса содержит метаданные о самом классе, включая список методов, которые класс реагирует.
кроме того, каждая структура класса имеет superclass
элемент, указывающий на его суперкласс, который отражается в иерархии метаклассов (т. е. superclass
еще один метакласс).
есть одно важное отличие: суперкласс NSObject
is nil
, а суперкласс NSObject
метакласс-это NSObject
. Другими словами,NSObject
метакласс наследует NSObject
'ы метод экземпляра. Как следствие, классы Objective-C не только отвечают на их определенные методы класса, они также отвечают на NSObject
методы экземпляра.
еще смущает? Грег Паркер написал отличный блог, который включает в себя очень полезную диаграмму, иллюстрирующую, как все это связано вместе:
архив Hamster Emporium-классы и метаклассы
редактировать
увы, в интернетах. Если браузер вы в настоящее время использование не отображает встроенные PDF-документы, вот ссылка непосредственно на диаграмму: