【问题标题】:Iterating over .plist dict. Type mismatch迭代 .plist 字典。类型不匹配
【发布时间】:2015-06-17 20:51:25
【问题描述】:

我正在尝试从 plist 文件中迭代嵌套的 dict。问题在于分解内容时的类型不匹配。我总是收到错误,即 NSObject、NSDict 和其他 NSstuff 无法转换为字符串变量,包括当我使用“(值)”、字符串()作为 .. 如何将 plist dict 子集元组分解为单独的变量时?

func LoadPlistContacts() {
    let path = NSBundle.mainBundle().pathForResource("ContactList", ofType: "plist")
    var AppContactsList = NSDictionary(contentsOfFile: path!)
    ListKeys = sorted(AppContactsList!.allKeys as! [String])

    for key in ListKeys {
        var (AppPersonName, AppPersonSurname, AppPersonCompany, AppPersonPhone) = AppContactsList[key]
        }

    }

更新: 我用字典而不是数组更改了 plist 并更新了代码,但类型不匹配仍然存在。正如 Airspeed Velocitynhgrif 在 cmets 中指出的那样,更新 plist 的示例确实变得更加混乱。如果带有注释错误的行没有解决它,我应该嵌套循环吗?谢谢。

var ListKeys: [String]!
var ListContacts: [String: String]!

func LoadPlistContacts() {

    if let path = NSBundle.mainBundle().pathForResource("ContactList", ofType: "plist") {
        var AppContactsList = NSDictionary(contentsOfFile: path)
        ListKeys = sorted(AppContactsList!.allKeys as! [String])
        ListContacts = sorted(AppContactsList!.allValues as [String:String]) { $0.0 < $1.0 }
        // I get an error [AnyObject] is not convertible to '[String:String]'

        for contact in ListContacts {

            let name =    contact["Forename"] ?? ""
            let surname = contact["Surname"] ?? ""
            let address = contact["Company"] ?? ""
            let phone =   contact["Phone"] ?? ""
        }

    }
    else {
        fatalError("Could not open Contacts plist")
    }
}

顺便说一句,Airspeed Velocity,爱你的博客!

【问题讨论】:

    标签: ios swift types plist


    【解决方案1】:

    Swift 不允许你像这样将数组解构为元组——主要是因为它不能保证工作(数组可能没有正确数量的条目)。

    您可能会发现在 plist 中包含另一个字典比数组更容易:

    然后像这样使用这些条目:

    if let path = NSBundle.mainBundle().pathForResource("ContactList", ofType: "plist"),
        contacts = NSDictionary(contentsOfFile: path) as? [String:[[String:String]]]
    {
        let sortedContacts = sorted(contacts) { lhs,rhs in lhs.0 < rhs.0 }
    
        // destructuring works here because contacts is known
        // at compile time to be an array of (key,value) pairs
        for (section, contactArray) in sortedContacts {
            for contact in contactArray {
                let name = contact["Forename"]
                let surname =  contact["Surname"]
                let address =  contact["Company"]
                let phone =  contact["Phone"]
                println(name,surname,address,phone)
            }   
        }
    }
    else {
        fatalError("Could not open Contacts plist")
    }
    

    请注意,当您取出这些条目时,它们将是可选的。这确实是这种方法的另一个好处——这意味着您可以省略 plist 中的条目,然后将它们默认为:

    // default to blank string for phone number
    let phone =   contact["Phone"] ?? ""
    

    或授权他们:

        for (section, contactArray) in contacts {
          for contact in contactArray {
            if let name =    contact["Forename"],
                   surname = contact["Surname"],
                   address = contact["Company"],
                   phone =   contact["Phone"]
            {
                println(name,surname,address,phone)
            }
            else {
                fatalError("Missing entry for \(section)")
            }
          }
        }
    

    注意,使用if let 比使用! 强制解包更可取,即使您使用的是在构建时配置的 plist 之类的东西,所以理论上永远不应该包含无效条目——因为这样,您可以进行显式错误处理,如果您不小心将错误数据放入 plist 中,这将有助于调试。

    【讨论】:

    • 我正在寻找答案,但你的答案很好地涵盖了所有要点。只是要评论提问者的 plist 结构与您的不完全匹配。它看起来更像这样:i.imgur.com/W03yayM.png
    • 啊,没错,好点。代码应该很容易适应,否则会是一个更混乱的例子。
    • 排序闭包测试中的.0访问器是什么,为什么需要?
    • @Price 字典以(key,value) 对的序列形式呈现。因此,如果您想通过键对字典进行排序但同时保留值,则需要一个仅比较键部分的排序谓词。由于密钥是该对中的第一个条目,因此以 .0 的形式访问它
    • 感谢小伙伴们的提示、更新的代码和 plist、更新的问题,请为最终确定提供一点帮助!谢谢!
    猜你喜欢
    • 2018-04-06
    • 1970-01-01
    • 2014-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-15
    相关资源
    最近更新 更多