我正在参与「启航方案」

本文主要对Swift的反射完成有一个根本的知道,经过JSON解析来知道反射以及过错的实际运用。

主要内容

  1. Mirror的运用
  2. 过错Error的运用

1、 Mirror

Swift是一门静态言语,没有像OC中Runtime那样的运行时操作。但是Swift标准库中供给了反射机制,用来动态访问成员信息,这就是Mirror。(当然远没有Runtime那样强壮)

1.1 根本运用

代码:

/*
 1、运用
 */
class WYTeacher: NSObject {
    var age: Int = 18
}
var t = WYTeacher()
let mirror = Mirror(reflecting: t.self)
for pro in mirror.children{
    print("\(String(describing: pro.label)): \(pro.value)")
}
//Optional("age"): 18

阐明:

  • 传入的是一个目标
  • 获取到MIrror目标,经过它就能够获取到t目标的成员,别离经过label、value获取特点和值

1.2 Mirror知道

Mirror的初始化:

public init(reflecting subject: Any)

阐明:

  • 进入Mirror初始化办法,发现传入的类型是Any,
  • 正是这个原因,我们才能够直接传t
  • 创立在给定实例上进行反射的反射目标
  • 假如subject的类型恪守CustomReflectable协议,生成的mirror由customMirror特点决定

children

public let children: Mirror.Children

//进入Children,发现是一个AnyCollection,接纳一个泛型
public typealias Children = AnyCollection<Mirror.Child>

//进入Child,发现是一个元组类型,由可选的标签和值构成,
public typealias Child = (label: String?, value: Any)

阐明:

  • children的类型为Children
  • 而Children是AnyCollection<Mirror.Child>的别号,是一切Child的集合
  • Child又是一个元组,由label、value组成
  • 别离用来存储特点和值

2、JOSN的完成

经过反射能够很轻松的获取到一个目标的成员,因而我们能够用来进行JSON解析,将一个目标转换成JSON格局

代码:

/*
 2、JSON解析
 */
//Int、String恪守协议
extension Int: CustomJSONMap{}
extension String: CustomJSONMap{}
//1、界说一个JSON解析协议
protocol CustomJSONMap {
    func jsonMap() -> Any
}
//2、供给一个默许完成
extension CustomJSONMap{
    func jsonMap() -> Any{
        let mirror = Mirror(reflecting: self)
        //递归停止条件
        guard !mirror.children.isEmpty else {
            return self
        }
        //字典,用于存储json数据
        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("当时-\(children.value)-没有恪守协议")
            }
        }
        return keyValue
    }
}
//3、让类恪守协议(注意:类中特点的类型也需求恪守协议,否则无法解析)
class WYTeacher: CustomJSONMap {
    var age = 18
    var name = "WY"
}
//运用
var t = WYTeacher()
print(t.jsonMap())

阐明:

  • 专门界说一个用来进行JSON解析的协议,这样能够给你恣意类型的目标进行解析,只需求这个类型恪守该协议即可
  • 这儿的完成也就是拿到目标的成员,别离存储到字典中,之后返回
  • 这儿进行了递归调用,由于有可能特点本身也是一个目标。以一个字典的方式再存储到这个key的value上
  • 类中特点的类型也需求恪守协议,由于这儿涉及到递归调用

3、Error的运用

在上文对于过错的处理是仅仅进行打印,这样并不规范,Swift中也供给了Error的处理方式。

Error的知道能够看我的另一篇博客Swift语法(十)Error

3.1 Error

Swift中,供给了Error协议来标识当时应用程序发生过错的状况。struct、Class、enum都能够恪守该协议,自界说过错。

代码:

//界说过错类型
enum JSONMapError: Error{
    case emptyKey
    case notConformProtocol
}
protocol CustomJSONMap {
    func jsonMap() throws -> Any
}
//2、供给一个默许完成
extension CustomJSONMap{
    func jsonMap() throws -> Any{
        let mirror = Mirror(reflecting: self)
        //递归停止条件
        guard !mirror.children.isEmpty else {
            return self
        }
        //字典,用于存储json数据
        var keyValue: [String: Any] = [:]
        //遍历
        for children in mirror.children {
            if let value = children.value as? CustomJSONMap {
                if let keyName = children.label {
                    //递归
                    keyValue[keyName] = try value.jsonMap()
                }else{
                    throw JSONMapError.emptyKey
                }
            }else{
                throw JSONMapError.notConformProtocol
            }
        }
        return keyValue
    }
}
var t = WYTeacher()
print(try t.jsonMap())

阐明:

  • 界说一个Error的枚举
  • 能够运用throw抛出异常
  • 办法中经过throws将过错抛出
  • 可能抛出异常的函数需求运用try调用,防止编译报错
  • 但是仅仅运用try调用,没有进行处理,这样会闪退
  • 能够运用try … catch进行过错处理。详细的处理能够看另一篇博客,这儿不再赘述

3.2 LocalError协议

假如仅仅用Error还不足以表达更翔实的过错信息,能够运用LocalizedError协议,其界说如下

界说:

public protocol LocalizedError : Error {
    /// A localized message describing what error occurred.过错描绘
    var errorDescription: String? { get }
    /// A localized message describing the reason for the failure.失败原因
    var failureReason: String? { get }
    /// A localized message describing how one might recover from the failure.建议
    var recoverySuggestion: String? { get }
    /// A localized message providing "help" text if the user requests help.协助
    var helpAnchor: String? { get }
}

阐明:

  • LocalError协议供给了多种特点
  • 我们能够给协议的这些特点添加描绘,这样在过错处理时就能够进行打印

运用: 此刻不给Int和String恪守CustomJSONMap,因而会走.notConformProtocol的分支

//界说更详细的过错信息
extension JSONMapError: LocalizedError{
    var errorDescription: String?{
        switch self {
        case .emptyKey:
            return "key为空"
        case .notConformProtocol:
            return "没有恪守协议"
        }
    }
}
var t = WYTeacher()
do{
    try t.jsonMap()
}catch{
    print(error.localizedDescription)
}

运行结果:

Swift底层探索(七)Swift的反射Mirror的实现和错误处理

3.3 CustomNSError协议

CustomNSError相当于OC中的NSError,其界说如下,有三个默许特点

界说:

public protocol CustomNSError : Error {
    /// The domain of the error.
    static var errorDomain: String { get }
    /// The error code within the given domain.
    var errorCode: Int { get }
    /// The user-info dictionary.
    var errorUserInfo: [String : Any] { get }
}

运用:

//CustomNSError相当于NSError
extension JSONMapError: CustomNSError{
    var errorCode: Int{
        switch self {
        case .emptyKey:
            return 404
        case .notConformProtocol:
            return 504
        }
    }
}
var t = WYTeacher()
do{
    try t.jsonMap()
}catch{
    print((error as? JSONMapError)?.errorCode)
}

运行结果:

Swift底层探索(七)Swift的反射Mirror的实现和错误处理

4、总结

  • Swift运用Mirror完成反射功用,能够动态获取目标的特点
  • 经过Mirror能够完成JSON的解析
  • Error是swift中过错类型的根本协议
  • 其间LocalizedError、CustomNSError都恪守Error,他们能够供给更详细的信息
  • try调用可能发生过错信息的函数