编写通用Swift方法从属性列表中加载数据

时间:2016-03-12 10:25:30

标签: ios swift generics functional-programming

我有一个从属性列表中加载字典数组的方法。然后我将这些字典数组更改为定义的自定义类型的数组; 我想用泛型形式编写该方法,所以我用我期望的类型调用该方法,然后方法加载它并返回我的自定义类型的数组而不是字典

func loadPropertyList(fileName: String) -> [[String:AnyObject]]?
{
    if let path = NSBundle.mainBundle().pathForResource(fileName, ofType: "plist")
    {
        if let plistXML = NSFileManager.defaultManager().contentsAtPath(path)
        {
            do {
                if let temp = try NSPropertyListSerialization.propertyListWithData(plistXML, options: .Immutable, format: nil) as? [[String:AnyObject]]
                {
                    return temp
                }
            }catch{}
        }
    }

    return nil
}


//

func loadList<T>(fileName: String) -> [T]?{//**Here the answer I am expecting**}

1 个答案:

答案 0 :(得分:1)

我假设您的功能是从Plist中读取作品而您不想要继承NSObject

由于Swift反射不支持设置值,因此如果没有您想要的每种类型的实现,这是不可能的。

然而,它可以以一种非常优雅的方式完成。

struct PlistUtils { // encapsulate everything
    static func loadPropertyList(fileName: String) -> [[String:AnyObject]]? {
        if let path = NSBundle.mainBundle().pathForResource(fileName, ofType: "plist") {
            if let plistXML = NSFileManager.defaultManager().contentsAtPath(path) {
                do {
                    if let temp = try NSPropertyListSerialization.propertyListWithData(plistXML, options: .Immutable, format: nil) as? [[String:AnyObject]] {
                        return temp
                    }
                } catch {
                    return nil
                }
            }
        }
        return nil
    }
}

此协议将以通用方式使用以获取类型名称并读取相应的Plist。

protocol PListConstructible {

    static func read() -> [Self]

}

此协议将用于实现键值设置器。

protocol KeyValueSettable {

    static func set(fromKeyValueStore values:[String:AnyObject]) -> Self

}

这是两者的组合,用于生成对象数组。这确实要求Plist以Type类型命名。

extension PListConstructible where Self : KeyValueSettable {

    static func read() -> [Self] {
        let name = String(reflecting: self)
        var instances : [Self] = []
        if let data = PlistUtils.loadPropertyList(name) {
            for entry in data {
                instances.append(Self.set(fromKeyValueStore: entry))
            }
        }
        return instances
    }
}

这是一些类型。

struct Some : PListConstructible {

    var alpha : Int = 0
    var beta : String = ""

}

您所要做的就是实现Key Value setter,现在可以从Plist中读取它。

extension Some : KeyValueSettable {

    static func set(fromKeyValueStore values: [String : AnyObject]) -> Some {
        var some = Some()
        some.alpha = (values["alpha"] as? Int) ?? some.alpha
        some.beta = (values["beta"] as? String) ?? some.beta
        return some
    }
}

这就是你使用它的方式。

Some.read()