gpt4 book ai didi

objective-c - 为什么类 NSObject 上的某些方法(-retainWeakReference、-allowsWeakReference、+load、+initialize)不能在运行时添加到其他类中?

转载 作者:太空狗 更新时间:2023-10-30 03:19:12 25 4
gpt4 key购买 nike

在运行时创建 Class NSObject 的副本 MyNSObject 很简单:

首先,创建一个新的 class pair .

Class MyNSObject = objc_allocateClassPair(nil, "MyNSObject", 0);

其次从 NSObject 中读取方法、协议(protocol)和 ivar,并将它们添加到新类中。

uint instanceMethodCount;
Method *instanceMethodArray = class_copyMethodList([NSObject class], &instanceMethodCount);
for (int i = 0; i < instanceMethodCount; i++) {
Method method = *(instanceMethodArray + i);
SEL selector = method_getName(method);
IMP implementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
BOOL success = class_addMethod(MyNSObject, selector, implementation, types);
}
free(instanceMethodArray);

uint protocolCount;
Protocol **protocolArray = class_copyProtocolList([NSObject class], &protocolCount);
for (int i = 0; i < protocolCount; i++) {
Protocol *protocol = *(protocolArray + i);
BOOL success = class_addProtocol(MyNSObject, protocol);
}
free(protocolArray);

uint ivarCount;
Ivar *ivarArray = class_copyIvarList([NSObject class], &ivarCount);
for (int i = 0; i < ivarCount; i++) {
Ivar ivar = *(ivarArray + i);
const char *name = ivar_getName(ivar);
const char *typeEncoding = ivar_getTypeEncoding(ivar);
NSUInteger size, alignment;
NSGetSizeAndAlignment(typeEncoding, &size, &alignment);
BOOL success = class_addIvar(MyNSObject, name, size, alignment, typeEncoding);
}
free (ivarArray);

第三,从NSObject的元类中读取方法,并将它们添加到新的元类中。

uint classMethodCount;
Method *classMethodArray = class_copyMethodList(object_getClass([NSObject class]), &classMethodCount);
for (int i = 0; i < classMethodCount; i++) {
Method method = *(classMethodArray + i);
SEL selector = method_getName(method);
IMP implementation = method_getImplementation(method);
const char *types = method_getTypeEncoding(method);
BOOL success = class_addMethod(object_getClass(MyNSObject), selector, implementation, types);
}
free(classMethodArray);

最后,注册类对。

objc_registerClassPair(MyNSObject);

好吧,这几乎就是这么简单。这有几个问题。好吧,一对夫妇。如果我们要在末尾但在第一个 for block 内添加以下行

if (!success) {
NSLog(@"unable to add method with selector named %@ to class MyNSObject", NSStringFromSelector(selector));
}

和末尾但在最后一个 for block 内的以下行

if (!success) {
NSLog(@"unable to add method with selector name %@ to metaclass MyNSObject", NSStringFromSelector(selector));
}

然后我们会看到如下输出:

unable to add method with selector name retainWeakReference to class MyNSObject
unable to add method with selector name allowsWeakReference to class MyNSObject
unable to add method with selector name load to metaclass MyNSObject
unable to add method with selector name initialize to metaclass MyNSObject

这是怎么回事?类(相应的元类)是否“开箱即用”地实现了 retainWeakReference 和 allowsWeakReferenc(相应的加载和初始化)?

引用资料:1. Cocoa with Love - What is a meta-class in Objective-C?
2. Stack Overflow - Justin Spahr-Summers response to "How can one obtain the sizeof a type for which one has an encoding?"

最佳答案

NSObject 是一个比预期更有趣的野兽。通常人们会想到 map

method_getName: Method -> SEL

一对一。即人们通常认为 method_getName(methodA) == method_getName(methodB) 以防万一 methodA == methodB。鼓励人们这样想:不能在编码过程中通过 @interface 创建一个类,它有多个具有相同选择器的方法,也不能使用 将两个具有相同选择器的方法添加到一个类中class_addMethod() 在运行时。

但是,显然可以手动完成。下面的代码演示了这一点。此代码获取 NSObject 上的所有实例方法并打印出每个名为“retainWeakReference”或“allowsWeakReference”的方法,然后获取 NSObject< 上的所有方法/strong> 并打印出每一个名为“initialize”或“load”的文件。

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,c16@0:8)
NSObject implements method(allowsWeakReference,0x7fff8a120b05,c16@0:8)
NSObject implements method(retainWeakReference,0x7fff80ad6db0,c16@0:8)
NSObject implements method(allowsWeakReference,0x7fff80ad6d90,c16@0:8)
metaNSObject implements method(load,0x7fff8a09e4f2,v16@0:8)
metaNSObject implements method(initialize,0x7fff8a00cb89,v16@0:8)
metaNSObject implements method(load,0x7fff80a57670,v16@0:8)
metaNSObject implements method(initialize,0x7fff80a133d0,v16@0:8)

因此,现在很明显,NSObject 对于每个选择器都有两个实现 -retainWeakReference-allowsWeakReference+load+初始化。这些是 NSObject 上仅有的四种方法,它们有多个实现,这是由问题中的代码报告的唯一四种无法添加到 的事实证明的>MyNSObject.

一个接近于作为问题答案的陈述是,您不能将具有相同选择器的多个方法添加到在运行时通过 class_addMethod() 创建的类。但是,特别是在运行时使用 objc_allocateClassPair() “开箱即用”创建的类没有实现任何方法。

关于objective-c - 为什么类 NSObject 上的某些方法(-retainWeakReference、-allowsWeakReference、+load、+initialize)不能在运行时添加到其他类中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8283401/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com