Ответ 1
NSObject - еще более интересный зверь, чем ожидалось. Обычно мы думаем о карте
method_getName: Method -> SEL
как один к одному. Обычно считается, что method_getName(methodA) == method_getName(methodB)
на всякий случай methodA == methodB
. Можно подумать об этом: нельзя создавать класс во время кодирования через @interface
, который имеет несколько методов с одним и тем же селектором, а также не может добавить два метода с тем же селектором в класс, используя class_addMethod()
во время выполнения.
Однако, очевидно, это возможно сделать вручную. Следующий код демонстрирует это. Этот код получает все методы экземпляра в NSObject и печатает каждый из них с именем "preserveWeakReference" или "allowWeakReference", а затем получает все методы класса в NSObject и печатает каждый один из них называется "инициализировать" или "загрузить".
uint NSObjectInstanceMethodCount;
Method *NSObjectInstanceMethodArray = class_copyMethodList([NSObject class], &NSObjectInstanceMethodCount);
for (int i = 0; i < NSObjectInstanceMethodCount; i++) {
Method method = *(NSObjectInstanceMethodArray + i);
SEL selector = method_getName(method);
IMP implementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
if (strcmp(selector, "retainWeakReference") == 0 || strcmp(selector, "allowsWeakReference") == 0) {
NSLog(@"NSObject implements method(%s,%p,%s)", selector, implementation, types);
}
}
uint NSObjectClassMethodCount;
Method *NSObjectClassMethodArray = class_copyMethodList(object_getClass([NSObject class]), &NSObjectClassMethodCount);
for (int i = 0; i < NSObjectClassMethodCount; i++) {
Method method = *(NSObjectClassMethodArray + i);
SEL selector = method_getName(method);
IMP implementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
if (strcmp(selector, "initialize") == 0 || strcmp(selector, "load") == 0) {
NSLog(@"metaNSObject implements method(%s,%p,%s)", selector, implementation, types);
}
}
Результат не тот, который можно было бы, помимо предыдущего наращивания, ожидать:
NSObject implements method(retainWeakReference,0x7fff8a120b1f,[email protected]:8)
NSObject implements method(allowsWeakReference,0x7fff8a120b05,[email protected]:8)
NSObject implements method(retainWeakReference,0x7fff80ad6db0,[email protected]:8)
NSObject implements method(allowsWeakReference,0x7fff80ad6d90,[email protected]:8)
metaNSObject implements method(load,0x7fff8a09e4f2,[email protected]:8)
metaNSObject implements method(initialize,0x7fff8a00cb89,[email protected]:8)
metaNSObject implements method(load,0x7fff80a57670,[email protected]:8)
metaNSObject implements method(initialize,0x7fff80a133d0,[email protected]:8)
Итак, как теперь очевидно, NSObject имеет две реализации для каждого из селекторов -retainWeakReference
, -allowsWeakReference
, +load
и +initialize
. Это единственные четыре метода в NSObject, для которых существует несколько реализаций, что подтверждается тем фактом, что они были единственными четырьмя, указанными в коде в вопросе, поскольку они не могут быть добавлены к MyNSObject.
Утверждение, которое приближается к подсчету в качестве ответа на вопрос, заключается в том, что вы не можете добавлять несколько методов с тем же селектором в класс, созданный во время выполнения через class_addMethod()
. В частности, однако, нет, никакие методы не реализуются классом, созданным во время выполнения, с objc_allocateClassPair()
"из коробки".