如何在 Swift 中不使用 NSDictionary 读取 Plist?

问题描述 投票:0回答:3

我已经在 Swift 2 中使用过这个方法了

var myDict: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist") {
myDict = NSDictionary(contentsOfFile: path)
}

但不知道如何在 Swift3 中读取 plist 而不使用 NSDictionary(文件内容:路径)

ios swift dictionary swift3 nsdictionary
3个回答
32
投票

原生 Swift 方式是使用

PropertyListSerialization

if let url = Bundle.main.url(forResource:"Config", withExtension: "plist") {
   do {
     let data = try Data(contentsOf:url)
     let swiftDictionary = try PropertyListSerialization.propertyList(from: data, format: nil) as! [String:Any]
      // do something with the dictionary
   } catch {
      print(error)
   }
}

您还可以将

NSDictionary(contentsOf:
与类型转换一起使用:

if let url = Bundle.main.url(forResource:"Config", withExtension: "plist"),
   let myDict = NSDictionary(contentsOf: url) as? [String:Any] {
   print(myDict)
}

但你明确写道:不使用 NSDictionary(contentsOf...

基本上不要在 Swift 中不进行强制转换就使用

NSDictionary
,你会丢弃重要的类型信息。


同时(Swift 4+)还有更方便的

PropertyListDecoder
,它能够将 Plist 直接解码为模型。


6
投票

PropertyListDecoder可用于将plist文件直接解码为对象。

1:示例 Plist 文件(sample.plist)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>key1</key>
    <string>valua for key1</string>
    <key> key2</key>
    <string>valua for key1</string>
    <key>CustomClass1</key>
    <dict>
        <key>customClass1_key</key>
        <string>customClass1_value</string>
    </dict>
    <key>CustomClass2</key>
    <dict>
        <key>customClass2_kek</key>
        <string>customClasse_value</string>
    </dict>
</dict>
</plist>

2:plist对应的模型

struct PlistConfiguration: Codable {
    var key1:String?
    var customClass1Obj: CustomClass1?
    var customClass2Obj: CustomClass2?
    
    private enum CodingKeys : String, CodingKey {
        case key1 = "key1"
        case customClass1Obj = "CustomClass1"
        case customClass2Obj = "CustomClass2"
    }
}

2.1:嵌套模型

struct CustomClass1: Codable {
    var customClass1_key:String?
    private enum CodingKeys : String, CodingKey {
        case customClass1_key = "customClass1_key"
    }
}

2.2:嵌套模型

struct CustomClass2: Codable {
    var customClass2_key: String?
    private enum CodingKeys : String, CodingKey {
        case customClass2_key = "customClass2_key"
    }
}

3:从主应用程序包中读取 Plist

func parseConfig() -> PlistConfiguration {
    let url = Bundle.main.url(forResource: "sample", withExtension: "plist")!
    let data = try! Data(contentsOf: url)
    let decoder = PropertyListDecoder()
    return try! decoder.decode(PlistConfiguration.self, from: data)
}

1
投票

在现代 Swift 环境中我使用这样的东西:

import Foundation

public extension Bundle {

  func plist<As>(from resource: String) -> As? where As: Decodable {
    guard let plist = Bundle.main.url(forResource: resource, withExtension: "plist") else { return nil }
    let decoder = PropertyListDecoder()
    do {
      let data = try Data(contentsOf: plist)
      return try decoder.decode(As.self, from: data)
    } catch { return nil }
  }

}
© www.soinside.com 2019 - 2024. All rights reserved.