Runtime源码 protocol(协议)

一、概述

协议定义了一个纲领性的接口,所有类都可以选择实现。它主要是用来定义一套对象之间的通信规则。protocol也是我们设计时常用的一个东西,相对于直接继承的方式,protocol则偏向于组合模式。他使得两个毫不相关的类能够相互通信,从而实现特定的目标。因为OC是单继承的,由于不支持多继承,所以很多时候都是用Protocol和Category来代替实现"多继承"。

二、底层实现

在objc4-723中protocol的定义如下:

struct protocol_t : objc_object {
	const char *mangledName;
    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;
    // Fields below this point are not always present on disk.
    const char **_extendedMethodTypes;
    const char *_demangledName;
    property_list_t *_classProperties;

    const char *demangledName();
    ...
};

复制代码

我们可以看到protocol继承自objc_object,里面的字段基本算是清晰,主要结构如下:

  • mangledName 和 _demangledName
    这是来源于C++的name mangling(命名重整)技术,在C++里面用来区别重载是的函数。

  • protocols
    它是protocol_list_t类型的指针,保存了这个协议所遵守的协议;

  • instanceMethods
    实例方法列表

  • calssMethods
    类方法列表

  • optionalInstanceMethods
    可选择实现的实例方法,在声明时用@optional关键字修饰的实例方法

  • optionalClassMethods
    可选择实现的类方法,在声明时用@optional关键字修饰的类方法

  • instanceProperties
    实例属性

  • _classProperties
    类属性,比较少见

    @property (nonatomic, strong) NSString *name;//通过实例调用
    @property (class, nonatomic, strong) NSString *className;//通过类名调用
    复制代码

三、 常用方法

  • protocol_copyPropertyList
    runtime提供了两个方法:
objc_property_t *
protocol_copyPropertyList(Protocol *proto, unsigned int *outCount)
{
    return protocol_copyPropertyList2(proto, outCount, 
                                      YES/*required*/, YES/*instance*/);
}


objc_property_t *
protocol_copyPropertyList2(Protocol *proto, unsigned int *outCount, 
                           BOOL isRequiredProperty, BOOL isInstanceProperty)
{
    if (!proto  ||  !isRequiredProperty) {
        // Optional properties are not currently supported.
        if (outCount) *outCount = 0;
        return nil;
    }

    rwlock_reader_t lock(runtimeLock);

    property_list_t *plist = isInstanceProperty
        ? newprotocol(proto)->instanceProperties
        : newprotocol(proto)->classProperties();
    return (objc_property_t *)copyPropertyList(plist, outCount);
}

复制代码

// Optional properties are not currently supported.
这里指明了可选属性现在还不支持,这就是没有可选属性的原因

  • conformsToProtocol()
+ (BOOL)conformsToProtocol:(Protocol *)protocol {
    if (!protocol) return NO;
    for (Class tcls = self; tcls; tcls = tcls->superclass) {
        if (class_conformsToProtocol(tcls, protocol)) return YES;
    }
    return NO;
}

- (BOOL)conformsToProtocol:(Protocol *)protocol {
    if (!protocol) return NO;
    for (Class tcls = [self class]; tcls; tcls = tcls->superclass) {
        if (class_conformsToProtocol(tcls, protocol)) return YES;
    }
    return NO;
}
复制代码

两个方法都是遍历类的继承集体,调用class_conformsToProtocol方法,其实现如下:

BOOL class_conformsToProtocol(Class cls, Protocol *proto_gen)
{
    protocol_t *proto = newprotocol(proto_gen);
    
    if (!cls) return NO;
    if (!proto_gen) return NO;

    rwlock_reader_t lock(runtimeLock);

    assert(cls->isRealized());

    for (const auto& proto_ref : cls->data()->protocols) {
        protocol_t *p = remapProtocol(proto_ref);
        if (p == proto || protocol_conformsToProtocol_nolock(p, proto)) {
            return YES;
        }
    }

    return NO;
}
复制代码

把class的protocols取出来,并与传入的protocol做比较,如果地址相同直接返回,或者协议"继承"的层级中满足条件:

/***********************************************************************
* protocol_conformsToProtocol_nolock
* Returns YES if self conforms to other.
* Locking: runtimeLock must be held by the caller.
**********************************************************************/
static bool 
protocol_conformsToProtocol_nolock(protocol_t *self, protocol_t *other)
{
    runtimeLock.assertLocked();

    if (!self  ||  !other) {
        return NO;
    }

    // protocols need not be fixed up

    if (0 == strcmp(self->mangledName, other->mangledName)) {
        return YES;
    }

    if (self->protocols) {
        uintptr_t i;
        for (i = 0; i < self->protocols->count; i++) {
            protocol_t *proto = remapProtocol(self->protocols->list[i]);
            if (0 == strcmp(other->mangledName, proto->mangledName)) {
                return YES;
            }
            if (protocol_conformsToProtocol_nolock(proto, other)) {
                return YES;
            }
        }
    }

    return NO;
}
复制代码

递归处理,对比协议的mangledName,有相同的就返回YES。

参考:
协议protocol
Protocol

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: OpenPLC Runtime是一款基于C++编写的开放源代码的PLC软件。使用OpenPLC Runtime可以在各种不同操作系统上实现PLC程序的开发和运行,包括Windows、Linux和MacOS等系统。 OpenPLC Runtime源码是完全开放的,因此能够满足用户基于自己的应用需求对软件进行二次开发。在对OpenPLC Runtime进行二次开发时,用户可以自主选择不同的编程语言,从而实现更加灵活多样化的PLC应用程序。 OpenPLC Runtime源码拥有完备的文档和注释,方便用户理解和学习。此外,OpenPLC Runtime源码还被广泛应用于工业控制领域,如数控系统、机器人等。它不仅支持各种连接方式,如Modbus TCP/RTU,还支持多个PLC通讯协议,如S7,Modbus Slave和Ethernet/IP等通讯协议,有着灵活多变的运行模式。 总之,OpenPLC Runtime源码是一款优秀的PLC软件源码,能够充分满足用户的PLC开发需求,并为用户提供多种选择和应用场景。 ### 回答2: OpenPLC Runtime是一个开源的PLC运行时环境,采用C++编写,支持多种输入输出设备和通信协议,包括Modbus、Ethernet/IP、Profinet等。 OpenPLC Runtime源码可以在GitHub上找到,由OpenPLC项目团队维护。源码包含了PLC运行时的核心代码和对应的设备驱动程序。 在编译和安装OpenPLC Runtime之前,需要安装相应的开发工具和依赖库,包括编译器、make工具、Boost库、Libmodbus等。编译时需要指定目标设备类型和通信协议以生成相应的二进制可执行文件。 OpenPLC Runtime支持多种编程语言和PLC编程软件,包括Ladder Logic、ST、C、Python等。用户可以根据自己的需求选择适合自己的编程语言和编程工具进行PLC编程。同时,OpenPLC Runtime还提供了Web界面和RESTful API以方便用户进行PLC程序的监控和控制。 总之,OpenPLC Runtime源码是一个强大的PLC运行时环境,为工业自动化控制系统提供了一个灵活、开放、可定制的解决方案。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值