swift--Runtime、反射

Runtime


class Teacher{
    var age: Int = 18
    func teach(){
        print("teach")
    }
}
let t = Teacher()
func test(){
    var methodCount:UInt32 = 0
    let methodlist = class_copyMethodList(Teacher.self, &methodCount)
    for i in 0..

运⾏这段代码你会发现,当前不管是我们的⽅法列表还是我们的属性列表,此次此刻都是为空的。如果将当前的⽅法和属性添加上@objc,此刻代码会输出我们当前的 teach ⽅法和 age 属性。但是此刻对于我们的 OC 来说是没有办法使⽤的。

  • 对于纯 Swift 类来说,没有 动态特性。⽅法和属性不加任何修饰符的情况下。这个时候其实已经不具 备我们所谓的 Runtime 特性了,这和上一章的⽅法调度(V-Table调度)是不谋⽽合的。 dynamic (动态特性) 对于纯 Swift 类,⽅法和属性添加 @objc 标识的情况下,当前我们可以通过 Runtime API 拿到,但 是在我们的 OC 中是没法进⾏调度的。
  • 对于继承⾃ NSObject 类来说,如果我们想要动态的获取当前的属性和⽅法,必须在其声明前添加 @objc 关键字,⽅法交换: 添加dynamic的标识。否则也是没有办法通过 Runtime API 获取的。

反射

反射就是可以动态获取类型、成员信息,在运⾏时可以调⽤⽅法、属性等⾏为的特性。上⾯我们分析过 了,对于⼀个纯 Swift 类来说,并不⽀持我们直接像 OC 那样操作;但是 Swift 标准库依然提供了反射机 制让我们访问成员信息, 反


class Teacher{
    var age: Int = 18
    var height:Double = 1.88
}
var t = Teacher()
let mirror = Mirror(reflecting: t)

for pro in mirror.children{
    print("\(pro.label):\(pro.value)")
}
·····················
ptional("age"):18
Optional("height:Double"):1.88

可以封装成一个协议获取属性值

protocol CustomJSONMap{
    func jsonMap() -> Any
}
extension CustomJSONMap{
    func jsonMap() -> Any{
        let mirror = Mirror(reflecting: self)
        guard !mirror.children.isEmpty else {return self}
        var keyValue: [String: Any] = [:]
        for children in mirror.children{
            if let value = children.value as? CustomJSONMap{
                if let keyName = children.label {
                    keyValue[keyName] = value.jsonMap()
                }else{
                    print("key是nil")
                }
            }else{
                print("没有遵守")
            }
        }
        return keyValue
    }
}
extension Int:CustomJSONMap{}
extension String:CustomJSONMap{}

class Teacher: CustomJSONMap {
    var age = 10
    var name = "js"
}

var t = Teacher()
print(t.jsonMap())

错误处理

Swift 提供 Error 协议来标识当前应⽤程序发⽣错误的情况, Error 的定义如下:

public protocol Error{ }

所以不管是我们的 structClassenum 我们都可以通过遵循这个协议来表示⼀个错误。这⾥我 们选择 enum

enum JSONMapError: Error{
    case emptyKey
    case notConformProtocol
}

我们在发生错误的地方用throw抛出错误,然后在返回值之前添加throws提示有错误需要处理。
try
使⽤ try 关键字有两个注意点:⼀个还是 try? ,⼀个是 try!

  • try? :返回的是⼀个可选类型,这⾥的结果就是两类,⼀类是成功,返回具体的字典值;⼀类就错 误,但是具体哪⼀类错误我们不关系,统⼀返回了⼀个nil
  • try! 表示你对这段代码有绝对的⾃信,这⾏代码绝对不会发⽣错误!

如果直接使用try就会向上级抛出。

do...catch

do {
            try 语句
              成功处理语句组
} catch 匹配错误 {
            错误处理语句组
}
catch 匹配错误 {
            错误处理语句组
}

在try 语句中可以产生错误,当然也可能不会产生错误,如果有错误发生,catch就会处理错误。catch代码块可以有多个,错误由哪个catch代码块处理是由catch后面的错误匹配与否而定的。错误类型的多少就决定了catch可以有多少。

LocalError

如何你觉得仅仅使⽤ Error 并不能达到你想要详尽表达错误信息的⽅式,可以使⽤ LocalError 协议

extension JSONMapError: LocalizedError{
    var errorDescription: String?{
        switch self {
        case .emptyKey:
            return "emptyKey"
        case .notConformProtocol:
            return "notConformProtocol"
        }
    }
}

mirror 源码分析

  internal init(internalReflecting subject: Any,
              subjectType: Any.Type? = nil,
              customAncestor: Mirror? = nil)
  {
//获取类型
    let subjectType = subjectType ?? _getNormalizedType(subject, type: type(of: subject))
    //获取属性长度
    let childCount = _getChildCount(subject, type: subjectType)

首先搜索_getNormalizedType

@_silgen_name("swift_reflectionMirror_normalizedType")
internal func _getNormalizedType(_: T, type: Any.Type) -> Any.Type

实际调用的是swift_reflectionMirror_normalizedType
通过@_silgen_name ,swift可以调用c语言此名字的方法

// func _getNormalizedType(_: T, type: Any.Type) -> Any.Type
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
                                                      const Metadata *type,
                                                      const Metadata *T) {
  return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
}



auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
          const F &f) -> decltype(f(nullptr))
{
  const Metadata *type;
  OpaqueValue *value;
  std::tie(type, value) = unwrapExistential(T, passedValue);
  
  if (passedType != nullptr) {
    type = passedType;
  }
  
  auto call = [&](ReflectionMirrorImpl *impl) {
    impl->type = type;
    impl->value = value;
    auto result = f(impl);
    return result;
  };
......
}


// Abstract base class for reflection implementations.
struct ReflectionMirrorImpl {
  const Metadata *type;
  OpaqueValue *value;
}

这里就根据metadata来获取类型,在赋给impl返回

static std::tuple
unwrapExistential(const Metadata *T, OpaqueValue *Value) {
  // If the value is an existential container, look through it to reflect the
  // contained value.
  // TODO: Should look through existential metatypes too, but it doesn't
  // really matter yet since we don't have any special mirror behavior for
  // concrete metatypes yet.
  while (T->getKind() == MetadataKind::Existential) {
    auto *existential
      = static_cast(T);

    // Unwrap the existential container.
    T = existential->getDynamicType(Value);
    Value = existential->projectValue(Value);

    // Existential containers can end up nested in some cases due to generic
    // abstraction barriers.  Repeat in case we have a nested existential.
  }
  return std::make_tuple(T, Value);
}

以结构体的metadata为例查看

struct TargetStructMetadata : public TargetValueMetadata 

struct TargetValueMetadata : public TargetMetadata {
...

  /// An out-of-line description of the type.
//关于源数据的描述
  ConstTargetMetadataPointer
    Description;
...
}

TargetMetadata里只有一个kind


class TargetValueTypeDescriptor
    : public TargetTypeContextDescriptor 

class TargetTypeContextDescriptor
    : public TargetContextDescriptor{

  /// The name of the type.
  TargetRelativeDirectPointer Name;
}

这个Name里就记录着关于类型的字符串。

using TargetRelativeDirectPointer
  = typename Runtime::template RelativeDirectPointer;

class RelativeDirectPointer :
  private RelativeDirectPointerImpl


class RelativeDirectPointerImpl {

private:
  /// The relative offset of the function's entry point from *this.
  Offset RelativeOffset;


public:
  using ValueTy = T;//当前值
  using PointerTy = T*;//当前指针
  PointerTy get() const & {
    // Check for null.
    if (Nullable && RelativeOffset == 0)
      return nullptr;
    
    // The value is addressed relative to `this`.
    uintptr_t absolute = detail::applyRelativeOffset(this, RelativeOffset);
    return reinterpret_cast(absolute);
  }

}

static inline uintptr_t applyRelativeOffset(BasePtrTy *basePtr, Offset offset) {
  static_assert(std::is_integral::value &&
                std::is_signed::value,
                "offset type should be signed integer");

  auto base = reinterpret_cast(basePtr);
  // We want to do wrapping arithmetic, but with a sign-extended
  // offset. To do this in C, we need to do signed promotion to get
  // the sign extension, but we need to perform arithmetic on unsigned values,
  // since signed overflow is undefined behavior.
  auto extendOffset = (uintptr_t)(intptr_t)offset;
  return base + extendOffset;
}

通过地址,在通过存储在里面的相对地址偏移获得信息

count

case MetadataKind::Struct: {
      StructImpl impl;
      return call(&impl);
    }

之前call返回的结构体是StructImpl类型的


struct StructImpl : ReflectionMirrorImpl {
  bool isReflectable() {//是否可反射
    const auto *Struct = static_cast(type);
    const auto &Description = Struct->getDescription();
    return Description->isReflectable();
  }

  intptr_t count() {
    if (!isReflectable()) {
      return 0;
    }

    auto *Struct = static_cast(type);
    return Struct->getDescription()->NumFields;
  }
...
}


  const TargetStructDescriptor *getDescription() const {
    return llvm::cast>(this->Description);
  }



///结构体的描述,我们需要找出所有的属性



class TargetValueTypeDescriptor
    : public TargetTypeContextDescriptor {
...

  /// The number of stored properties in the struct.
  /// If there is a field offset vector, this is its length.
  uint32_t NumFields;
  /// The offset of the field offset vector for this struct's stored
  /// properties in its metadata, if any. 0 means there is no field offset
  /// vector.
  uint32_t FieldOffsetVectorOffset;
}

}

class TargetValueTypeDescriptor
    : public TargetTypeContextDescriptor 

class TargetTypeContextDescriptor
    : public TargetContextDescriptor {
public:
  /// The name of the type.
  TargetRelativeDirectPointer Name;

  /// A pointer to the metadata access function for this type.
  ///
  /// The function type here is a stand-in. You should use getAccessFunction()
  /// to wrap the function pointer in an accessor that uses the proper calling
  /// convention for a given number of arguments.
  TargetRelativeDirectPointer AccessFunctionPtr;
  
  /// A pointer to the field descriptor for the type, if any.
  TargetRelativeDirectPointer Fields;


struct TargetContextDescriptor {
  /// Flags describing the context, including its kind and format version.
  ContextDescriptorFlags Flags;
  
  /// The parent context, or null if this is a top-level context.
  RelativeContextPointer Parent;
...
}

属性

StructImpl中还有个方法来获取熟悉的名称和属性的值


  AnyReturn subscript(intptr_t i, const char **outName,
                      void (**outFreeFunc)(const char *)) {
    auto *Struct = static_cast(type);

    if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
      swift::crash("Swift mirror subscript bounds check failure");

    // Load the offset from its respective vector.
    auto fieldOffset = Struct->getFieldOffsets()[i];

    Any result;
    StringRef name;
    FieldType fieldInfo;
//获取属性名称
    std::tie(name, fieldInfo) = getFieldAt(type, i);
    assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
    
    *outName = name.data();
    *outFreeFunc = nullptr;
    
    auto *bytes = reinterpret_cast(value);
    auto *fieldData = reinterpret_cast(bytes + fieldOffset);
    
    bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
    if (!didLoad) {
      result.Type = fieldInfo.getType();
      auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
      result.Type->vw_initializeWithCopy(opaqueValueAddr,
                                         const_cast(fieldData));
    }

    return AnyReturn(result);
  }

通过getFieldAt获取属性名称

getFieldAt(const Metadata *base, unsigned index) {
...

  auto *fields = baseDesc->Fields.get();
  if (!fields)
    return failedToFindMetadata();
  
  const FieldDescriptor &descriptor = *fields;
  auto &field = descriptor.getFields()[index];
  // Bounds are always valid as the offset is constant.
  auto name = field.getFieldName();
...
}

可以看到是对MetadataDesc里的fields进行操作来获取的


  /// A pointer to the field descriptor for the type, if any.
  TargetRelativeDirectPointer Fields;

class FieldDescriptor {
  const FieldRecord *getFieldRecordBuffer() const {
    return reinterpret_cast(this + 1);
  }

public:
  const RelativeDirectPointer MangledTypeName;
  const RelativeDirectPointer Superclass;

  FieldDescriptor() = delete;

  const FieldDescriptorKind Kind;
  const uint16_t FieldRecordSize;
  const uint32_t NumFields;

swift 代码


struct StructMetadata {
    var kind : Int
    var typeDescriptor : UnsafeMutablePointer
}

struct StructDescriptor {
    var flags: Int32
    var parent:Int32
    var name : RelativeDirectPointer//type的名称
    var AccessFunctionPtr: RelativeDirectPointer
    var Fields: RelativeDirectPointer
    var NumFields:Int32
    var FieldOffsetVectorOffset:Int32
    
}

struct FieldDescriptor {
    var MangledTypeName: RelativeDirectPointer
    var Superclass: RelativeDirectPointer
    var kind : UInt16
    var FieldRecordSize : Int16
    var NumFields : Int32
    var fields:FieldRecord //连续的内存空间
}


struct FieldRecord {
    var Flags: Int32
    var MangledTypeName: RelativeDirectPointer
    var FieldName: RelativeDirectPointer
}

struct RelativeDirectPointer {
    var offset:Int32
    mutating func get() -> UnsafeMutablePointer {
        let offset = self.offset
        
        return withUnsafePointer(to: &self) { p in
            return UnsafeMutablePointer(mutating: UnsafeRawPointer(p).advanced(by: numericCast(offset)).assumingMemoryBound(to: T.self))
        }
    }
}

struct Teacher {
    var age = 18
    var name = "js"
}



var t = Teacher()

var t1 = Teacher.self
//按位强转
//将Teacher的metadata这八个字节数据吗,强行转到StructMetadata中,这时候kind和desc都会有值
let ptr = unsafeBitCast(Teacher.self as Any.Type, to: UnsafeMutablePointer.self)

let namePtr = ptr.pointee.typeDescriptor.pointee.name.get()
print(String(cString: namePtr))
print(ptr.pointee.typeDescriptor.pointee.NumFields)

let fieldDescriptorPtr = ptr.pointee.typeDescriptor.pointee.Fields.get()

let recordPtr = withUnsafePointer(to: &fieldDescriptorPtr.pointee.fields) {
    return UnsafeMutablePointer(mutating: UnsafeRawPointer($0).assumingMemoryBound(to: FieldRecord.self).advanced(by: 1))
}

print("--------")
print(String(cString: recordPtr.pointee.FieldName.get()))
dump(t)

你可能感兴趣的:(swift--Runtime、反射)