当您将@protocol(SomeProtocol)
作为参数传递给方法时,结果指针是否可以被视为具有静态存储持续时间?
现在考虑到协议是在编译时定义的,在.h文件中,这意味着它的指针在程序的整个生命周期内是相同的,并且可以安全地复制,在某种意义上,在运行时是静态的 - 时间?
答案 0 :(得分:2)
关于Protocol
指针是什么有一些非常明显的混淆,所以我会试图澄清对此的任何困惑。
早在ObjC的旧时代,协议根本就不存在。因此,当NeXT的API需要多重继承时,他们将其作为自己的类“入侵”为语言,并使用特殊语法修改编译器以接受它。
在ObjC2推出之前一直运行良好,并且协议将作为官方语言(和运行时API)功能添加,但这会导致一些向后兼容性问题,因为我们已经有{{1由NeXT定义的类。
出现的解决方案是保持Protocol类,但弃用它。因此,我们在技术上仍然具有Protocol
类lying around in the runtime,但是没有一种方法在ObjC2中工作(实际情况就是很多不同的旧构造,例如Protocol
选择器,forward::
和其他一些小事,但我离题了。
您不应该(读取不能)向此类发送消息 - 虽然它在技术上仍然是一个对象,但您不应期望它符合应用程序中存在的其他对象的相同约定(协议?)。
然后,解决方案是使用前缀为objc_msgSendv
的运行时中的函数,例如:
protocol_
代替protocol_getName()
。-name
代替protocol_conformsToProtocol()
等
请注意,在协议类的当前实现下,这些方法实际上仍然可以被调用,并且只是它们的C函数对应物的垫片。
话虽如此,如果所有协议都是使用-conformsTo:
获得的,那么它们与运行时的当前版本保证具有“静态”存储,我们可以通过{{ 3}}:
objc_getProtocol
没有协议的副本,并且每个后续调用都将返回相同的指针。这也适用于使用/***********************************************************************
* objc_getProtocol
* Get a protocol by name, or return nil
* Locking: read-locks runtimeLock
**********************************************************************/
Protocol *objc_getProtocol(const char *name)
{
rwlock_read(&runtimeLock);
Protocol *result = (Protocol *)NXMapGet(protocols(), name);
rwlock_unlock_read(&runtimeLock);
return result;
}
表达式,它基本上(尽管不完全是,还有一些其他编译器魔法)被认为是对@protocol(name)
的调用。
现在 - 理论上,某人可能故意创建协议“对象”的副本,因为结构非常简单,如implementation所述:
objc_getProtocol
(请注意,这是一个模仿objective-c对象的C ++结构,如果你试图自己模拟它会导致一些困难。)
这里要注意的重要一点是,只需对运行时给你的协议指针执行struct protocol_t : objc_object {
const char *name;
struct protocol_list_t *protocols;
method_list_t *instanceMethods;
method_list_t *classMethods;
method_list_t *optionalInstanceMethods;
method_list_t *optionalClassMethods;
property_list_t *instanceProperties;
uint32_t size; // sizeof(protocol_t)
uint32_t flags;
const char **extendedMethodTypes;
};
就会导致很少的问题,因此,你应该总是使用{{1}用于比较协议,它将检查协议的字段以确保它们实际上是等效的,即使它们有不同的指针。
简单地将memcpy
视为静态是完全正常的,并且是在代码中引用协议的正确方法。
但是,请注意,与任何运行时功能一样,这可能会随着API的另一个版本,编译器,ABI,目标体系结构和其他内容而发生变化,因此请务必阅读最新信息可以谈论这个主题!