Objective c 协议对象是否具有静态存储持续时间?
当您将Objective c 协议对象是否具有静态存储持续时间?,objective-c,objective-c-runtime,objective-c-protocol,Objective C,Objective C Runtime,Objective C Protocol,当您将@protocol(SomeProtocol)作为参数传递给方法时,结果指针是否可以被视为具有静态存储持续时间 现在考虑到协议是在编译时在.h文件中定义的,这是否意味着它的指针在程序的整个生命周期中都是相同的,并且在某种意义上可以安全地称为在运行时是静态的?TL;医生:是的,有一些警告。 关于什么是协议指针,有一些非常明显的混淆,因此我将尝试澄清有关这方面的任何混淆 回到ObjC的旧时代,协议根本不存在。因此,当NeXT的API需要多重继承时,他们将其作为自己的类“黑客”到一种语言中,并使
@protocol(SomeProtocol)
作为参数传递给方法时,结果指针是否可以被视为具有静态存储持续时间
现在考虑到协议是在编译时在.h文件中定义的,这是否意味着它的指针在程序的整个生命周期中都是相同的,并且在某种意义上可以安全地称为在运行时是静态的?TL;医生:是的,有一些警告。
关于什么是协议
指针,有一些非常明显的混淆,因此我将尝试澄清有关这方面的任何混淆
回到ObjC的旧时代,协议根本不存在。因此,当NeXT的API需要多重继承时,他们将其作为自己的类“黑客”到一种语言中,并使用特殊语法修改编译器以接受这一点
它工作得很好,直到ObjC2推出,协议将被添加为官方语言(和运行时API)特性,但这导致了一些向后兼容性问题,因为我们已经有了一个由NeXT定义的Protocol
类
产生的解决方案是保留Protocol类,但不推荐它。因此,从技术上讲,我们仍然有协议
类,但没有一个方法在ObjC2中工作(事实上,对于许多不同的旧构造,例如转发::
选择器、objc_msgSendv
和其他一些小东西,这是事实,但我离题了)
您不应该(read-can)向此类发送消息-虽然从技术上讲它仍然是一个对象,但您不应该期望它符合应用程序中存在的其他对象的相同约定(协议?)
因此,解决方案是在运行时中使用前缀为协议的函数,例如:
protocol\u getName()
而不是-name
协议\u conformsToProtocol()
而不是-conformsTo:
等等
请注意,在协议类的当前实现下,这些方法实际上仍然可以调用,并且只是它们的C函数对应项的一个垫片
话虽如此,如果您的所有协议都是通过使用objc_getProtocol
获得的,那么在当前版本的运行时中,它们保证具有“静态”存储,正如我们可以通过以下内容看到的:
不复制协议,后续每次调用都将返回相同的指针。这也适用于使用@protocol(name)
表达式,该表达式基本上可以被视为对objc\u getProtocol
的调用(尽管不完全是,还有其他一些编译器魔法)
现在-然而,从理论上讲,有人可以故意创建协议“对象”的副本,因为结构非常简单,如下所述:
(注意这是一个模仿ObjuleC对象的C++结构,如果你自己尝试模仿它,会导致一些困难)。
这里需要注意的重要一点是,对运行时提供给您的协议指针执行
memcpy
,很少会引起问题,因此,您应该始终使用protocol\u isEqual()
来比较协议,这将检查协议的字段,以确保它们实际上是等效的,即使它们有不同的指针
不过,简单地将协议*
视为静态协议完全可以,这是在代码中引用协议的正确方法
但是,请注意,与任何运行时特性一样,这些特性都可能随API的其他版本、编译器、ABI、目标体系结构和其他内容而发生更改,因此请务必阅读有关该主题的最新信息 同样在您发布的相同链接中,声明您可以以与普通类相同的方式查看协议。默认情况下它们是静态的吗?我不这么认为。因此我认为协议和它们的指针不会被认为是静态的。不是真的,邮报说协议是一个类。。。SomeProtocol是该类的实例,因此它有一个指针。如果我们谈论的是MyClass,它是NSObject的一个子类,它没有指针,因为我们谈论的是MyClass本身。为了让MyClass“有一个指针”,我们需要创建一个MyClass的实例,而这个实例有一个指针。MyClass是一个工厂,它可以创建对象,并且每个对象都有一个指针。混淆的是SomeProtocol,在编写时它看起来像是在创建一个子类,但实际上编译器会利用它创建Protocol类的一个实例,并将您在.h文件中编写的属性提供给它。SomeProtocol实际上是一个实例,而不是Protocol类的子类。结论是,您在程序中定义的所有SomeProtocol都会被解析,在运行时它们都是Protocol类的实例,它们是一般意义上的对象,您可以向OneProtocol发送消息,这样或那样做,它就会做出响应。否则它只会说。。。不然而,这句话“简单地将协议*当作静态的完全可以,并且是在代码中引用协议的正确方式。”正是我想要的。谢谢你提供的所有其他信息,它为我提供了完全理解答案所需的背景知识。非常感谢。
/***********************************************************************
* 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;
}
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;
};