演员协议<>字符串(或其他)

时间:2016-01-06 15:31:51

标签: swift swift2

我有一个名为 User()

的课程
class User {
    var name: String?
    var email: String?
    var id: String?
    var identification_number: String?
    var phone_number: NSMutableArray?    
    var user_group: String?
    var date: NSDate?
}

我希望得到类中的所有变量及其各自的值。我想在这种情况下使用镜像

func updateProfile(user: User) {

    let mirror = Mirror(reflecting: user)

    for child in mirror.children {
        print("\(child.label!), \(child.value)")
    }

}

我的问题是,如何将child.value转换为任何其他数据类型,比如String? 我只是发现child.value属于 Protocol 'Any'

2 个答案:

答案 0 :(得分:3)

child.value具有Any类型。从Any转换为可选项会带来一些问题,幸运的是Sandy Chapman在this post中提供了一个非常好的解决方案。

使用他的功能,代码看起来像这样:

func castToOptional<T>(x: Any) -> T? {
    return Mirror(reflecting: x).descendant("Some") as? T
}

func updateProfile(user: User) {
    let mirror = Mirror(reflecting: user)
    for child in mirror.children {
        print("\(child.label!), \(child.value)")
        if let stringVal = castToOptional(child.value) as String? {
            print("Unwrapped a string: \(stringVal)")
        } else if let stringVal = child.value as? String {
            print("Found a non-optional string: \(stringVal)")
        }
    }
}

因此,如果您正在寻找字符串,则需要查找可选字符串和非可选字符串。这适用于您需要检查的所有类型。

答案 1 :(得分:2)

创建用于扩展Optional<Any>类型的协议以返回其非可选值:

private protocol AnyOptional {
    var objectValue: Any? { get }
}

extension Optional: AnyOptional {
    var objectValue: Any? {
        switch self {
        case .None:
            return nil
        case .Some(_):
            return self! as Any
        }
    }
}

此后,您可以使用AnyOptional协议作为类型,并将Any?个对象转换为AnyOptional,然后允许我们使用.objectValue AnyOptional属性}}

class User {
    var name: String?
    var email: String?
    var id: String = "Default ID" // Lets try also with one non-optional
    var identification_number: String?
    var phone_number: NSMutableArray?
    var user_group: String?
    var date: NSDate?
}

var myUser = User()
myUser.name = "John"
myUser.phone_number = ["+44", "701 23 45 67"]

func updateProfile(user: User) {

    let mirror = Mirror(reflecting: user)

    for child in mirror.children {
        let value : Any = (child.value as? AnyOptional)?.objectValue ?? child.value

        switch(value) {
        case let obj as String: print("String item: User.\(child.label!) = " + obj)
        case let obj as NSMutableArray: print("NSMutableArray item: User.\(child.label!) = \(obj)")
        case let obj as NSDate: print("NSDate item: User.\(child.label!) = \(obj)")
        case _ : print("Non-initialized optional item: User.\(child.label!) = \(value)")
        }
    }
}

产生以下输出

updateProfile(myUser)

/*
String item: User.name = John
Non-initialized optional item: User.email = nil
String item: User.id = Default ID
Non-initialized optional item: User.identification_number = nil
NSMutableArray item: User.phone_number = (
    "+44",
    "701 23 45 67"
)
Non-initialized optional item: User.user_group = nil
Non-initialized optional item: User.date = nil       */

使用此解决方案的好处是它将解开&#34;展开&#34;可选的非零值child.value(不包含"Optional(...)"填充)以及作为可选的child.value的值,无需单独打开&#34;展开&#34;对于这两个案件。在上面的switch情况下,您可以处理需要使用的User对象的任何非零属性,而不仅仅是String,而是User中的任何类型obj 1}}类。 switch案例中的nil属性将属于您的类的每个非零属性的非可选类型。默认情况对应于值为master(未分配)的选项。