Class written in Swift

栏目: Swift · 发布时间: 7年前

内容简介:之前纯粹的 Swift 类(没继承自其实如果 Swift 类的属性类型是继承自

之前 TBUIAutoTest 有个 issue ,我发现原因跟 Swift 有关,在解决问题时顺带稍微研究了下 Swift 编写的类。

Swift Class 与 Ivar

纯粹的 Swift 类(没继承自 NSObject )在 Runtime 上有很大的坑。虽然 Runtime 的接口都能调用,但因为 Class 实现和构成有很大差异,所以需要谨慎对待。比如 Swift 没有 Ivar 的概念,相应的 Runtime 接口也只是尽可能的封装,不保证返回的内容正确。Swift 将成员变量和属性统一起来,并统一存储和管理。

其实如果 Swift 类的属性类型是继承自 NSObject 的话,还是可以通过 Ivar 相关 Runtime 函数获取到内容的。这也是 TBUIAutoTest 能够兼容 Swift 的原因。有些 Objective-C 类型在 Swift 有对应的替代,比如 NSStringString 。编译器会自动转换接口和类型,但在这些类型上的属性获取 Ivar 依然有些问题。比如使用 object_getIvar 就会 BAD_ACCESS

Swift Class Runtime Name

在比较早的 Swift 版本,debug 时我们看到的 Swift 的类名都是一串很长很乱的字符串,其实那是经过 Objective-C Runtime Mangle 后的产物。大概的规则如下:

  1. 前缀是 “_Tt”
  2. 如果是 Class,还会再加一个 “C”,Protocol 会跟着一个 “P”
  3. Module名连着类名,并在每个名字前面标记字符串长度。

如今 Swift 正酝酿着一套新的 Mangle 规则,但要等 Objective-C Runtime 那边实现好新的 Demangle 后才能实施!有兴趣可以看下 mangleObjCRuntimeName 函数的实现。

现在 lldb 中打印 Swift 类型更加友好了,但是底层还是会生成一个 Runtime Name。在 $(SWIFT_MODULE_NAME)-Swift.h 文件中可以看到 Swift AST 对应 Objective-C 的头文件,里面就有 Swift Runtime Name。Swift 源码里有个 PrintAsObjC.cpp 文件,它的作用就是生成 Swift AST 头文件。

举个栗子:使用 NSClassFromString(@"_TtC19ClassWrittenInSwift11AppDelegate") 获取到的类是 ClassWrittenInSwift Module 中的 AppDelegate 类。

Swift Class Check

如何判断一个类是否用 Swift 写的呢?Runtime 中 Class 是有标志位的,只是没对外暴露接口而已。映射到 Runtime 源码中 Class 的内存模型,将标志位取出即可,关键代码如下。

struct yxy_objc_object {
    yxy_isa_t isa;
};

// class is a Swift class
#define FAST_IS_SWIFT         (1UL<<0)

struct yxy_class_data_bits_t {
    // Values are the FAST_ flags above.
    uintptr_t bits;
    bool getBit(uintptr_t bit)
    {
        return bits & bit;
    }
    bool isSwift() {
        return getBit(FAST_IS_SWIFT);
    }
};

struct yxy_objc_class : yxy_objc_object {
    // Class ISA;
    Class superclass;
    yxy_cache_t cache;             // formerly cache pointer and vtable
    yxy_class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags
};

BOOL isWrittenInSwift(Class cls)
{
    if (!cls || !object_isClass(cls)) {
        return NO;
    }
    struct yxy_objc_class *objc_cls = (__bridge struct yxy_objc_class *)cls;
    bool isSwift = objc_cls->bits.isSwift();
    return isSwift;
}

实现很简单,封装了下: ClassWrittenInSwift

哎,自己的 Repo 真是越来越水了。

Swift Class Lazy Property

Swift 类的 lazy 属性的存储比较特殊,毕竟是懒加载。它的属性名有个后缀 “.storage”,所以在 Runtime 里获取属性名时要注意,使用时是要过滤掉后缀的。

写了个简单的接口获取 Swift 类中的 lazy 属性名列表,代码同样放在 ClassWrittenInSwift 里面了。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Docker——容器与容器云(第2版)

Docker——容器与容器云(第2版)

浙江大学SEL实验室 / 人民邮电出版社 / 2016-10 / 89.00元

本书根据Docker 1.10版和Kubernetes 1.2版对第1版进行了全面更新,从实践者的角度出发,以Docker和Kubernetes为重点,沿着“基本用法介绍”到“核心原理解读”到“高级实践技巧”的思路,一本书讲透当前主流的容器和容器云技术,有助于读者在实际场景中利用Docker容器和容器云解决问题并启发新的思考。全书包括两部分,第一部分深入解读Docker容器技术,包括Docker架......一起来看看 《Docker——容器与容器云(第2版)》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试