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{ }
所以不管是我们的 struct
、 Class
、 enum
我们都可以通过遵循这个协议来表示⼀个错误。这⾥我 们选择 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)