Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 协议对象是否具有静态存储持续时间?_Objective C_Objective C Runtime_Objective C Protocol - Fatal编程技术网

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;
};