如何在Swift中将plist作为字典?

Seb*_*ian 185 ios swift

我正在使用Apple的新Swift编程语言并遇到一些问题......

目前我正在尝试读取一个plist文件,在Objective-C中我将执行以下操作以将内容作为NSDictionary获取:

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Config" ofType:@"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:filePath];
Run Code Online (Sandbox Code Playgroud)

如何在Swift中将plist作为字典?

我假设我可以通过以下方式获得plist的路径:

let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist")
Run Code Online (Sandbox Code Playgroud)

当这工作时(如果它是正确的?):我如何将内容作为字典?

还有一个更普遍的问题:

可以使用默认的NS*类吗?我想是这样......或者我错过了什么?据我所知,默认框架NS*类仍然有效,可以使用吗?

Con*_*nor 263

你仍然可以在Swift中使用NSDictionaries:

对于Swift 4

 var nsDictionary: NSDictionary?
 if let path = Bundle.main.path(forResource: "Config", ofType: "plist") {
    nsDictionary = NSDictionary(contentsOfFile: path)
 }
Run Code Online (Sandbox Code Playgroud)

适用于Swift 3+

if let path = Bundle.main.path(forResource: "Config", ofType: "plist"),
   let myDict = NSDictionary(contentsOfFile: path){
    // Use your myDict here
}
Run Code Online (Sandbox Code Playgroud)

和旧版本的Swift

var myDict: NSDictionary?
if let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist") {
    myDict = NSDictionary(contentsOfFile: path)
}
if let dict = myDict {
    // Use your dict here
}
Run Code Online (Sandbox Code Playgroud)

NSClasses仍然可用,并且可以在Swift中使用.我认为他们可能希望尽快将焦点转移到swift,但目前swift API并不具备核心NSClasses的所有功能.

  • 这个答案已经过时了。即使在Swift 3中,您也绝对不应使用NSArray / NSDictionary来读取属性列表数据。“ PropertyListSerialization”(以及Swift 4中的“ Codable”协议)是合适的API。它提供了现代的错误处理,并且可以将数据直接转换为本机Swift集合类型。 (5认同)

phe*_*sta 139

如果我想将.plist转换为Swift字典,我就是这样做的:

if let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist") {
  if let dict = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
    // use swift dictionary as normal
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑Swift 2.0:

if let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist"), dict = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
    // use swift dictionary as normal
}
Run Code Online (Sandbox Code Playgroud)

编辑Swift 3.0:

if let path = Bundle.main.path(forResource: "Config", ofType: "plist"), let dict = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
        // use swift dictionary as normal
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为这是一个"最正确"的答案,直到有一个本地的快速方式来做到这一点. (3认同)

Ash*_*k R 47

swift 3.0中阅读Plist.

func readPropertyList() {
        var propertyListFormat =  PropertyListSerialization.PropertyListFormat.xml //Format of the Property List.
        var plistData: [String: AnyObject] = [:] //Our data
        let plistPath: String? = Bundle.main.path(forResource: "data", ofType: "plist")! //the path of the data
        let plistXML = FileManager.default.contents(atPath: plistPath!)!
        do {//convert the data to a dictionary and handle errors.
            plistData = try PropertyListSerialization.propertyList(from: plistXML, options: .mutableContainersAndLeaves, format: &propertyListFormat) as! [String:AnyObject]

        } catch {
            print("Error reading plist: \(error), format: \(propertyListFormat)")
        }
    }
Run Code Online (Sandbox Code Playgroud)

阅读更多 如何在SWIFT中使用房产列表(.PLIST).


ekr*_*off 41

Swift 4.0

您现在可以使用Decodable协议将.plist解码为自定义结构.我将回顾一个基本的例子,对于更复杂的.plist结构,我建议阅读Decodable/Encodable(这是一个很好的资源:https://benscheirman.com/2017/06/swift-json/ ).

首先将结构设置为.plist文件的格式.对于此示例,我将考虑具有根级别Dictionary和3个条目的.plist:1带有键"name"的字符串,1带有键"age"的Int和带有键"single"的1布尔值.这是结构:

struct Config: Decodable {
    private enum CodingKeys: String, CodingKey {
        case name, age, single
    }

    let name: String
    let age: Int
    let single: Bool
}
Run Code Online (Sandbox Code Playgroud)

很简单.现在很酷的部分.使用PropertyListDecoder类,我们可以轻松地将.plist文件解析为此结构的实例化:

func parseConfig() -> Config {
    let url = Bundle.main.url(forResource: "Config", withExtension: "plist")!
    let data = try! Data(contentsOf: url)
    let decoder = PropertyListDecoder()
    return try! decoder.decode(Config.self, from: data)
}
Run Code Online (Sandbox Code Playgroud)

没有更多的代码可以担心,而且它全部都在Swift中.更好的是,我们现在可以轻松使用Config结构的实例化:

let config = parseConfig()
print(config.name) 
print(config.age)
print(config.single) 
Run Code Online (Sandbox Code Playgroud)

这将打印.plist中"name","age"和"single"键的值.

  • @vadian当然你可以使用 `url(forResource: "Config", withExtension: "plist")` 我只是匹配OP在他们的代码中所做的事情作为比较点。至于用力打开所有东西,我尽量谨慎行事。我认为这对于 Swift 来说是一个基本问题。我宁愿确切地知道我的代码在任何情况下都会做什么,而不是崩溃。 (2认同)
  • @NaveenGeorgeThoppan,如果您使用此示例作为字典,那么它就是`decoder.decode([Config] .self,from:data)`。(注意[Config]周围的括号) (2认同)

Tom*_* C. 21

这个答案使用Swift本机对象而不是NSDictionary.

Swift 3.0

//get the path of the plist file
guard let plistPath = Bundle.main.path(forResource: "level1", ofType: "plist") else { return }
//load the plist as data in memory
guard let plistData = FileManager.default.contents(atPath: plistPath) else { return }
//use the format of a property list (xml)
var format = PropertyListSerialization.PropertyListFormat.xml
//convert the plist data to a Swift Dictionary
guard let  plistDict = try! PropertyListSerialization.propertyList(from: plistData, options: .mutableContainersAndLeaves, format: &format) as? [String : AnyObject] else { return }
//access the values in the dictionary 
if let value = plistDict["aKey"] as? String {
  //do something with your value
  print(value)
}
//you can also use the coalesce operator to handle possible nil values
var myValue = plistDict["aKey"] ?? ""
Run Code Online (Sandbox Code Playgroud)


小智 16

我一直在使用Swift 3.0,并希望为更新的语法提供答案.另外,也许更重要的是,我使用PropertyListSerialization对象来完成繁重的工作,这比仅使用NSDictionary要灵活得多,因为它允许将Array作为plist的根类型.

下面是我正在使用的plist的截图.它有点复杂,以显示可用的功率,但这适用于plist类型的任何允许组合.

示例plist文件 如您所见,我正在使用Array of String:String字典来存储网站名称列表及其相应的URL.

我正在使用PropertyListSerialization对象,如上所述,为我做繁重的工作.此外,Swift 3.0变得更加"Swifty",因此所有对象名称都丢失了"NS"前缀.

let path = Bundle.main().pathForResource("DefaultSiteList", ofType: "plist")!
let url = URL(fileURLWithPath: path)
let data = try! Data(contentsOf: url)
let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil)
Run Code Online (Sandbox Code Playgroud)

上面的代码运行后plist会是类型Array<AnyObject>,但我们知道它的类型是什么,所以我们可以将它转换为正确的类型:

let dictArray = plist as! [[String:String]]
// [[String:String]] is equivalent to Array< Dictionary<String, String> >
Run Code Online (Sandbox Code Playgroud)

现在我们可以以自然的方式访问Array of String:String Dictionaries的各种属性.希望将它们转换为实际的强类型结构或类;)

print(dictArray[0]["Name"])
Run Code Online (Sandbox Code Playgroud)


67c*_*ies 8

最好使用本机词典和数组,因为它们已经过优化,可以与swift一起使用.话虽如此,你可以在swift中使用NS ...类,我认为这种情况需要保证.以下是如何实现它:

var path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist")
var dict = NSDictionary(contentsOfFile: path)
Run Code Online (Sandbox Code Playgroud)

到目前为止(在我看来)这是访问plist的最简单,最有效的方法,但是在未来我希望苹果会在原生词典中添加更多功能(例如使用plist).


小智 8

Swift - 读/写plist和文本文件....

override func viewDidLoad() {
    super.viewDidLoad()

    let fileManager = (NSFileManager .defaultManager())
    let directorys : [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory,NSSearchPathDomainMask.AllDomainsMask, true) as? [String]

    if (directorys != nil){
        let directories:[String] = directorys!;
        let dictionary = directories[0]; //documents directory


        //  Create and insert the data into the Plist file  ....
        let plistfile = "myPlist.plist"
        var myDictionary: NSMutableDictionary = ["Content": "This is a sample Plist file ........."]
        let plistpath = dictionary.stringByAppendingPathComponent(plistfile);

        if !fileManager .fileExistsAtPath(plistpath){//writing Plist file
            myDictionary.writeToFile(plistpath, atomically: false)
        }
        else{            //Reading Plist file
            println("Plist file found")

            let resultDictionary = NSMutableDictionary(contentsOfFile: plistpath)
            println(resultDictionary?.description)
        }


        //  Create and insert the data into the Text file  ....
        let textfile = "myText.txt"
        let sampleText = "This is a sample text file ......... "

        let textpath = dictionary.stringByAppendingPathComponent(textfile);
        if !fileManager .fileExistsAtPath(textpath){//writing text file
            sampleText.writeToFile(textpath, atomically: false, encoding: NSUTF8StringEncoding, error: nil);
        } else{
            //Reading text file
            let reulttext  = String(contentsOfFile: textpath, encoding: NSUTF8StringEncoding, error: nil)
            println(reulttext)
        }
    }
    else {
        println("directory is empty")
    }
}
Run Code Online (Sandbox Code Playgroud)


A.G*_*A.G 8

Swift 2.0:访问Info.Plist

我有一个名为CoachMarksDictionary的字典,在Info.Plist中有一个布尔值.我想访问bool值并使其成立.

let path = NSBundle.mainBundle().pathForResource("Info", ofType: "plist")!
  let dict = NSDictionary(contentsOfFile: path) as! [String: AnyObject]

  if let CoachMarksDict = dict["CoachMarksDictionary"] {
       print("Info.plist : \(CoachMarksDict)")

   var dashC = CoachMarksDict["DashBoardCompleted"] as! Bool
    print("DashBoardCompleted state :\(dashC) ")
  }
Run Code Online (Sandbox Code Playgroud)

写入Plist:

从自定义Plist中: - (从File-New-File-Resource-PropertyList中创建.添加了三个名为DashBoard_New,DashBoard_Draft,DashBoard_Completed的字符串)

func writeToCoachMarksPlist(status:String?,keyName:String?)
 {
  let path1 = NSBundle.mainBundle().pathForResource("CoachMarks", ofType: "plist")
  let coachMarksDICT = NSMutableDictionary(contentsOfFile: path1!)! as NSMutableDictionary
  var coachMarksMine = coachMarksDICT.objectForKey(keyName!)

  coachMarksMine  = status
  coachMarksDICT.setValue(status, forKey: keyName!)
  coachMarksDICT.writeToFile(path1!, atomically: true)
 }
Run Code Online (Sandbox Code Playgroud)

该方法可以称为

self.writeToCoachMarksPlist(" true - means user has checked the marks",keyName: "the key in the CoachMarks dictionary").
Run Code Online (Sandbox Code Playgroud)


Sco*_*ant 6

由于这个答案还没有出现,只是想指出您还可以使用 infoDictionary 属性将信息 plist 作为字典获取Bundle.main.infoDictionary

尽管如果您只对信息 plist 中的特定项目感兴趣,则Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) 可能会更快。

// Swift 4

// Getting info plist as a dictionary
let dictionary = Bundle.main.infoDictionary

// Getting the app display name from the info plist
Bundle.main.infoDictionary?[kCFBundleNameKey as String]

// Getting the app display name from the info plist (another way)
Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String)
Run Code Online (Sandbox Code Playgroud)


Suh*_*til 6

斯威夫特 5

如果您想获取某个键的特定值,那么我们可以使用以下扩展名,该扩展名在 Bundle 上使用infoDictionary属性。

Bundle.main.infoDictionary可用于获取info.plist表单字典中的所有值,因此我们可以使用object(forInfoDictionaryKey: key)Bundle 上的方法直接查询

extension Bundle {
    static func infoPlistValue(forKey key: String) -> Any? {
        guard let value = Bundle.main.object(forInfoDictionaryKey: key) else {
           return nil
        }
        return value
    }
}
Run Code Online (Sandbox Code Playgroud)

用法

guard let apiURL = Bundle.infoPlistValue(forKey: "API_URL_KEY") as? String else { return }
Run Code Online (Sandbox Code Playgroud)


Ken*_*yVB 5

实际上可以在1行中完成

    var dict = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("Config", ofType: "plist"))
Run Code Online (Sandbox Code Playgroud)


imt*_*mti 5

您可以通过以下方式使用SWIFT语言阅读plist:

let path = NSBundle.mainBundle().pathForResource("PriceList", ofType: "plist")
let dict = NSDictionary(contentsOfFile: path)
Run Code Online (Sandbox Code Playgroud)

读取单个字典值:

let test: AnyObject = dict.objectForKey("index1")
Run Code Online (Sandbox Code Playgroud)

如果要在plist中获得完整的多维词典:

let value: AnyObject = dict.objectForKey("index2").objectForKey("date")
Run Code Online (Sandbox Code Playgroud)

这是plist:

<plist version="1.0">
<dict>
<key>index2</key>
<dict>
    <key>date</key>
    <string>20140610</string>
    <key>amount</key>
    <string>110</string>
</dict>
<key>index1</key>
<dict>
    <key>amount</key>
    <string>125</string>
    <key>date</key>
    <string>20140212</string>
</dict>
</dict>
</plist>
Run Code Online (Sandbox Code Playgroud)


mre*_*dig 5

通过Nick的答案转换为便捷扩展:

extension Dictionary {
    static func contentsOf(path: URL) -> Dictionary<String, AnyObject> {
        let data = try! Data(contentsOf: path)
        let plist = try! PropertyListSerialization.propertyList(from: data, options: .mutableContainers, format: nil)

        return plist as! [String: AnyObject]
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

let path = Bundle.main.path(forResource: "plistName", ofType: "plist")!
let url = URL(fileURLWithPath: path)
let dict = Dictionary<String, AnyObject>.contentsOf(path: url)
Run Code Online (Sandbox Code Playgroud)

我愿意打赌,它也可以为数组创建类似的扩展