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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24045570/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 00:27:32  来源:igfitidea点击:

How do I get a plist as a Dictionary in Swift?

iosswift

提问by Sebastian

I am playing around with Apple's new Swiftprogramming language and have some problems...

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

Currently I'm trying to read a plist file, in Objective-C I would do the following to get the content as a NSDictionary:

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

NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Config" ofType:@"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:filePath];

How do I get a plist as a Dictionary in Swift?

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

I assume I can get the path to the plist with:

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

let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist")

When this works (If it's correct?): How do I get the content as a Dictionary?

当这有效时(如果正确?):如何将内容作为字典获取?

Also a more general question:

还有一个更普遍的问题:

Is it OK to use the default NS*classes? I think so...or am I missing something? As far as I know the default framework NS*classes are still valid and alright to use?

可以使用默认的NS*类吗?我想是的……还是我错过了什么?据我所知,默认框架NS*类仍然有效并且可以使用吗?

采纳答案by Ashok R

In swift 3.0Reading from Plist.

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)")
        }
    }

Read More HOW TO USE PROPERTY LISTS (.PLIST) IN SWIFT.

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

回答by Connor

You can still use NSDictionaries in Swift:

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

For Swift 4

对于 Swift 4

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

For Swift 3+

Swift 3+

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

And older versions of Swift

和旧版本的 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
}

The NSClasses are still available and perfectly fine to use in Swift. I think they'll probably want to shift focus to swift soon, but currently the swift APIs don't have all the functionality of the core NSClasses.

NSClasses 仍然可用并且完全可以在 Swift 中使用。我认为他们可能会很快将重点转移到 swift 上,但目前 swift API 没有核心 NSClasses 的所有功能。

回答by pheedsta

This is what I do if I want to convert a .plist to a Swift dictionary:

如果我想将 .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
  }
}

Edited for Swift 2.0:

为 Swift 2.0 编辑:

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

Edited for Swift 3.0:

为 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
}

回答by ekreloff

Swift 4.0

斯威夫特 4.0

You can now use the Decodable protocol to Decode a .plist into a custom struct. I will go over a basic example, for more complicated .plist structures I recommend reading up on Decodable/Encodable (a good resource is here: https://benscheirman.com/2017/06/swift-json/).

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

First setup your struct into the format of your .plist file. For this example I will consider a .plist with a root level Dictionary and 3 entries: 1 String with key "name", 1 Int with key "age", and 1 Boolean with key "single". Here is the struct:

首先将结构设置为 .plist 文件的格式。对于这个例子,我将考虑一个带有根级别字典和 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
}

Simple enough. Now the cool part. Using the PropertyListDecoder class we can easily parse the .plist file into an instantiation of this struct:

足够简单。现在是很酷的部分。使用 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)
}

Not much more code to worry about, and its all in Swift. Better yet we now have an instantiation of the Config struct that we can easily use:

无需担心更多代码,一切都在 Swift 中。更好的是,我们现在有了一个可以轻松使用的 Config 结构体实例:

let config = parseConfig()
print(config.name) 
print(config.age)
print(config.single) 

This Prints the value for the "name", "age", and "single" keys in the .plist.

这会打印 .plist 中“name”、“age”和“single”键的值。

回答by Tommie C.

This answer uses Swift native objects rather than NSDictionary.

此答案使用 Swift 本机对象而不是 NSDictionary。

Swift 3.0

斯威夫特 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"] ?? ""

回答by Nick

I have been working with Swift 3.0 and wanted to contribute an answer for the updated syntax. Additionally, and possibly more importantly, I am using the PropertyListSerializationobject to do the heavy lifting, which is a lot more flexible than just using the NSDictionary as it allows for an Array as the root type of the plist.

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

Below is a screenshot of the plist I am using. It is a littlecomplicated, so as to show the power available, but this will work for any allowable combination of plist types.

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

Sample plist fileAs you can see I am using an Array of String:String dictionaries to store a list of website names and their corresponding URL.

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

I am using the PropertyListSerializationobject, as mentioned above, to do the heavy lifting for me. Additionally, Swift 3.0 has become more "Swifty" so all of the object names have lost the "NS" prefix.

如上所述,我正在使用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)

After the above code runs plistwill be of type Array<AnyObject>, but we know what type it really is so we can cast it to the correct type:

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

let dictArray = plist as! [[String:String]]
// [[String:String]] is equivalent to Array< Dictionary<String, String> >

And now we can access the various properties of our Array of String:String Dictionaries in a natural way. Hopefully to convert them into actual strongly typed structs or classes ;)

现在我们可以以自然的方式访问字符串数组的各种属性:字符串字典。希望将它们转换为实际的强类型结构或类;)

print(dictArray[0]["Name"])

回答by Nithin Sathyan

Swift - Read/Write plist and text file....

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")
    }
}

回答by A.G

Swift 2.0 : Accessing Info.Plist

Swift 2.0:访问 Info.Plist

I have a Dictionary named CoachMarksDictionary with a boolean value in Info.Plist . I want to access the bool value and make it true.

我有一个名为 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) ")
  }

Writing To Plist:

写入 Plist:

From a Custom Plist:- (Make from File-New-File-Resource-PropertyList. Added three strings named : DashBoard_New, DashBoard_Draft, DashBoard_Completed)

来自自定义 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)
 }

The method can be called as

该方法可以称为

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

回答by 67cherries

It is best to use native dictionaries and arrays because they have been optimized for use with swift. That being said you can use NS... classes in swift and I think this situation warrants that. Here is how you would implement it:

最好使用本机字典和数组,因为它们已针对 swift 进行了优化。话虽如此,您可以快速使用 NS... 类,我认为这种情况是正确的。以下是您将如何实现它:

var path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist")
var dict = NSDictionary(contentsOfFile: path)

So far (in my opinion) this is the easiest and most efficient way to access a plist, but in the future I expect that apple will add more functionality (such as using plist) into native dictionaries.

到目前为止(在我看来)这是访问 plist 的最简单和最有效的方式,但在未来我预计苹果会在本地字典中添加更多功能(例如使用 plist)。

回答by mredig

Converted into a convenience extension via Nick's answer:

通过尼克的回答转换为便利扩展:

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]
    }
}

usage:

用法:

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

I'd be willing to bet that it would also work to create a similar extension for Arrays

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