简体   繁体   English

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

[英]How do I get a plist as a Dictionary in Swift?

I am playing around with Apple's new Swift programming 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?可以使用默认的NS*类吗? 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*类仍然有效并且可以使用吗?

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. NSClasses 仍然可用并且完全可以在 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.我认为他们可能会很快将重点转移到 swift 上,但目前 swift API 没有核心 NSClasses 的所有功能。

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
}

In swift 3.0 Reading 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)

Swift 4.0斯威夫特 4.0

You can now use the Decodable protocol to Decode a .plist into a custom struct.您现在可以使用 Decodable 协议将 .plist 解码为自定义结构。 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/ ).我将介绍一个基本示例,对于更复杂的 .plist 结构,我建议阅读 Decodable/Encodable(这里有一个很好的资源: https ://benscheirman.com/2017/06/swift-json/)。

First setup your struct into the format of your .plist file.首先将结构设置为 .plist 文件的格式。 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".对于这个例子,我将考虑一个带有根级别字典和 3 个条目的 .plist:1 个带有键“name”的字符串,1 个带有键“age”的 Int,以及带有键“single”的 1 个布尔值。 Here is the struct:这是结构:

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.无需担心更多代码,一切都在 Swift 中。 Better yet we now have an instantiation of the Config struct that we can easily use:更好的是,我们现在有了一个可以轻松使用的 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”键的值。

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"] ?? ""

I have been working with Swift 3.0 and wanted to contribute an answer for the updated syntax.我一直在使用 Swift 3.0 并希望为更新的语法提供答案。 Additionally, and possibly more importantly, I am using the PropertyListSerialization object 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.此外,可能更重要的是,我使用PropertyListSerialization对象来完成繁重的工作,这比仅使用 NSDictionary 灵活得多,因为它允许将 Array 作为 plist 的根类型。

Below is a screenshot of the plist I am using.下面是我正在使用的 plist 的屏幕截图。 It is a little complicated, so as to show the power available, but this will work for any allowable combination of plist types.有点复杂,以显示可用的功率,但这适用于任何允许的 plist 类型组合。

示例 plist 文件 As you can see I am using an Array of String:String dictionaries to store a list of website names and their corresponding URL.如您所见,我正在使用 String:String 字典数组来存储网站名称及其相应 URL 的列表。

I am using the PropertyListSerialization object, as mentioned above, to do the heavy lifting for me.如上所述,我正在使用PropertyListSerialization对象为我完成繁重的工作。 Additionally, Swift 3.0 has become more "Swifty" so all of the object names have lost the "NS" prefix.此外,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 plist will be of type Array<AnyObject> , but we know what type it really is so we can cast it to the correct type:上面的代码运行后plist的类型将是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"])

It is best to use native dictionaries and arrays because they have been optimized for use with swift.最好使用本机字典和数组,因为它们已针对 swift 进行了优化。 That being said you can use NS... classes in swift and I think this situation warrants that.话虽如此,您可以快速使用 NS... 类,我认为这种情况是正确的。 Here is how you would implement it:以下是您将如何实现它:

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)添加到本机词典中。

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

Swift 2.0 : Accessing Info.Plist Swift 2.0:访问 Info.Plist

I have a Dictionary named CoachMarksDictionary with a boolean value in Info.Plist .我有一个名为 CoachMarksDictionary 的字典,在 Info.Plist 中有一个布尔值。 I want to access the bool value and make it true.我想访问 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").

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我愿意打赌它也可以为数组创建类似的扩展

Since this answer isn't here yet, just wanted to point out you can also use the infoDictionary property to get the info plist as a dictionary, Bundle.main.infoDictionary .由于这个答案还没有出现,只是想指出您还可以使用 infoDictionary 属性将信息 plist 作为字典Bundle.main.infoDictionary

Although something like Bundle.main.object(forInfoDictionaryKey: kCFBundleNameKey as String) may be faster if you're only interested in a specific item in the info plist.尽管如果您只对信息 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)

Swift 5斯威夫特 5

If you want to fetch specific value for some key then we can use below extension which uses infoDictionary property on Bundle.如果你想获取某个键的特定值,那么我们可以使用下面的扩展,它在 Bundle 上使用infoDictionary属性。

Bundle.main.infoDictionary can be used to get all info.plist values in the form dictionary and so we can directly query using object(forInfoDictionaryKey: key) method on Bundle Bundle.main.infoDictionary可用于获取表单字典中的所有info.plist值,因此我们可以使用 Bundle 上的object(forInfoDictionaryKey: key)方法直接查询

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

Usage用法

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

实际上可以在 1 行中完成

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

You can read plist in SWIFT Language in this way:您可以通过以下方式阅读 SWIFT 语言中的 plist:

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

Read Single Dictionary value:读取单个字典值:

let test: AnyObject = dict.objectForKey("index1")

If you want to get full multi-dimensional dictionary in plist:如果你想在 plist 中获得完整的多维字典:

let value: AnyObject = dict.objectForKey("index2").objectForKey("date")

Here is the plist:这是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>

in my case I create a NSDictionary called appSettings and add all needed keys.就我而言,我创建了一个名为appSettingsNSDictionary并添加了所有需要的键。 For this case, the solution is:对于这种情况,解决方法是:

if let dict = NSBundle.mainBundle().objectForInfoDictionaryKey("appSettings") {
  if let configAppToken = dict["myKeyInsideAppSettings"] as? String {

  }
}

You can use that, I create a simple extension for Dictionary in github https://github.com/DaRkD0G/LoadExtension您可以使用它,我在 github https://github.com/DaRkD0G/LoadExtension 中为 Dictionary 创建了一个简单的扩展

extension Dictionary {
    /**
        Load a Plist file from the app bundle into a new dictionary

        :param: File name
        :return: Dictionary<String, AnyObject>?
    */
    static func loadPlistFromProject(filename: String) -> Dictionary<String, AnyObject>? {

        if let path = NSBundle.mainBundle().pathForResource("GameParam", ofType: "plist") {
            return NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject>
        }
        println("Could not find file: \(filename)")
        return nil
    }
}

And you can use that for load你可以用它来加载

/**
  Example function for load Files Plist

  :param: Name File Plist
*/
func loadPlist(filename: String) -> ExampleClass? {
    if let dictionary = Dictionary<String, AnyObject>.loadPlistFromProject(filename) {
        let stringValue = (dictionary["name"] as NSString)
        let intergerValue = (dictionary["score"] as NSString).integerValue
        let doubleValue = (dictionary["transition"] as NSString).doubleValue

        return ExampleClass(stringValue: stringValue, intergerValue: intergerValue, doubleValue: doubleValue)
    }
    return nil
}

Here is a bit shorter version, based on @connor 's answer这是一个更短的版本,基于@connor 的回答

guard let path = Bundle.main.path(forResource: "GoogleService-Info", ofType: "plist"),
    let myDict = NSDictionary(contentsOfFile: path) else {
    return nil
}

let value = dict.value(forKey: "CLIENT_ID") as! String?

Swift 3.0斯威夫特 3.0

if let path = Bundle.main.path(forResource: "config", ofType: "plist") {
    let dict = NSDictionary(contentsOfFile: path)

    // use dictionary
}

The easiest way to do this in my opinion.在我看来,这是最简单的方法。

Step 1 : Simple and fastest way to parse plist in swift 3+第 1 步:在 swift 3+ 中简单快速地解析 plist

extension Bundle {

    func parsePlist(ofName name: String) -> [String: AnyObject]? {

        // check if plist data available
        guard let plistURL = Bundle.main.url(forResource: name, withExtension: "plist"),
            let data = try? Data(contentsOf: plistURL)
            else {
                return nil
        }

        // parse plist into [String: Anyobject]
        guard let plistDictionary = try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: AnyObject] else {
            return nil
        }

        return plistDictionary
    }
}

Step 2: How to use:第2步:如何使用:

Bundle().parsePlist(ofName: "Your-Plist-Name")

I've created a simple Dictionary initializer that replaces NSDictionary(contentsOfFile: path) .我创建了一个简单的Dictionary初始值设定项来替换NSDictionary(contentsOfFile: path) Just remove the NS .只需删除NS

extension Dictionary where Key == String, Value == Any {

    public init?(contentsOfFile path: String) {
        let url = URL(fileURLWithPath: path)

        self.init(contentsOfURL: url)
    }

    public init?(contentsOfURL url: URL) {
        guard let data = try? Data(contentsOf: url),
            let dictionary = (try? PropertyListSerialization.propertyList(from: data, options: [], format: nil) as? [String: Any]) ?? nil
            else { return nil }

        self = dictionary
    }

}

You can use it like so:你可以像这样使用它:

let filePath = Bundle.main.path(forResource: "Preferences", ofType: "plist")!
let preferences = Dictionary(contentsOfFile: filePath)!
UserDefaults.standard.register(defaults: preferences)

Swift 4.0 iOS 11.2.6 list parsed and code to parse it, based on https://stackoverflow.com/users/3647770/ashok-r answer above.基于https://stackoverflow.com/users/3647770/ashok-r上面的回答,已解析 Swift 4.0 iOS 11.2.6 列表和解析它的代码。

<?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">
<array>
  <dict>
    <key>identity</key>
    <string>blah-1</string>
    <key>major</key>
    <string>1</string>
    <key>minor</key>
    <string>1</string>
    <key>uuid</key>
    <string>f45321</string>
    <key>web</key>
    <string>http://web</string>
</dict>
<dict>
    <key>identity</key>
    <string></string>
    <key>major</key>
    <string></string>
    <key>minor</key>
    <string></string>
    <key>uuid</key>
    <string></string>
    <key>web</key>
    <string></string>
  </dict>
</array>
</plist>

do {
   let plistXML = try Data(contentsOf: url)
    var plistData: [[String: AnyObject]] = [[:]]
    var propertyListFormat =  PropertyListSerialization.PropertyListFormat.xml
        do {
            plistData = try PropertyListSerialization.propertyList(from: plistXML, options: .mutableContainersAndLeaves, format: &propertyListFormat) as! [[String:AnyObject]]

        } catch {
            print("Error reading plist: \(error), format: \(propertyListFormat)")
        }
    } catch {
        print("error no upload")
    }

Here's the solution I found:这是我找到的解决方案:

let levelBlocks = NSDictionary(contentsOfFile: NSBundle.mainBundle().pathForResource("LevelBlocks", ofType: "plist"))
let test: AnyObject = levelBlocks.objectForKey("Level1")
println(test) // Prints the value of test

I set the type of test to AnyObject to silence a warning about an unexpected inference that could occur.我将test类型设置为AnyObjectAnyObject有关可能发生的意外推断的警告。

Also, it has to be done in a class method.此外,它必须在类方法中完成。

To access and save a specific value of a known type:要访问和保存已知类型的特定值:

let value = levelBlocks.objectForKey("Level1").objectForKey("amount") as Int
println(toString(value)) // Converts value to String and prints it

I use swift dictionaries but convert them to and from NSDictionaries in my file manager class like so:我使用 swift 字典,但在我的文件管理器类中将它们与 NSDictionaries 相互转换,如下所示:

    func writePlist(fileName:String, myDict:Dictionary<String, AnyObject>){
        let docsDir:String = dirPaths[0] as String
        let docPath = docsDir + "/" + fileName
        let thisDict = myDict as NSDictionary
        if(thisDict.writeToFile(docPath, atomically: true)){
            NSLog("success")
        } else {
            NSLog("failure")
        }

    }
    func getPlist(fileName:String)->Dictionary<String, AnyObject>{
        let docsDir:String = dirPaths[0] as String
        let docPath = docsDir + "/" + fileName
        let thisDict = NSDictionary(contentsOfFile: docPath)
        return thisDict! as! Dictionary<String, AnyObject>
    }

This seems the least troubling way to read and write but let's the rest of my code stay as swift as possible.这似乎是最不麻烦的读写方式,但让我的其余代码尽可能保持快速。

Plist is a simple Swift enum I made for working with property lists. Plist是我为处理属性列表而制作的一个简单的 Swift 枚举。

// load an applications info.plist data

let info = Plist(NSBundle.mainBundle().infoDictionary)
let identifier = info["CFBundleIndentifier"].string!

More examples:更多例子:

import Plist

// initialize using an NSDictionary
// and retrieve keyed values

let info = Plist(dict)
let name = info["name"].string ?? ""
let age = info["age"].int ?? 0


// initialize using an NSArray
// and retrieve indexed values

let info = Plist(array)
let itemAtIndex0 = info[0].value


// utility initiaizer to load a plist file at specified path
let info = Plist(path: "path_to_plist_file")

// we support index chaining - you can get to a dictionary from an array via
// a dictionary and so on
// don't worry, the following will not fail with errors in case
// the index path is invalid
if let complicatedAccessOfSomeStringValueOfInterest = info["dictKey"][10]["anotherKey"].string {
  // do something
}
else {
  // data cannot be indexed
}

// you can also re-use parts of a plist data structure

let info = Plist(...)
let firstSection = info["Sections"][0]["SectionData"]
let sectionKey = firstSection["key"].string!
let sectionSecret = firstSection["secret"].int!

Plist.swift Plist.swift

Plist itself is quite simple, here's its listing in case you to refer directly. Plist 本身非常简单,这里是它的列表,以防您直接参考。

//
//  Plist.swift
//


import Foundation


public enum Plist {

    case dictionary(NSDictionary)
    case Array(NSArray)
    case Value(Any)
    case none

    public init(_ dict: NSDictionary) {
        self = .dictionary(dict)
    }

    public init(_ array: NSArray) {
        self = .Array(array)
    }

    public init(_ value: Any?) {
        self = Plist.wrap(value)
    }

}


// MARK:- initialize from a path

extension Plist {

    public init(path: String) {
        if let dict = NSDictionary(contentsOfFile: path) {
            self = .dictionary(dict)
        }
        else if let array = NSArray(contentsOfFile: path) {
            self = .Array(array)
        }
        else {
            self = .none
        }
    }

}


// MARK:- private helpers

extension Plist {

    /// wraps a given object to a Plist
    fileprivate static func wrap(_ object: Any?) -> Plist {

        if let dict = object as? NSDictionary {
            return .dictionary(dict)
        }
        if let array = object as? NSArray {
            return .Array(array)
        }
        if let value = object {
            return .Value(value)
        }
        return .none
    }

    /// tries to cast to an optional T
    fileprivate func cast<T>() -> T? {
        switch self {
        case let .Value(value):
            return value as? T
        default:
            return nil
        }
    }
}

// MARK:- subscripting

extension Plist {

    /// index a dictionary
    public subscript(key: String) -> Plist {
        switch self {

        case let .dictionary(dict):
            let v = dict.object(forKey: key)
            return Plist.wrap(v)

        default:
            return .none
        }
    }

    /// index an array
    public subscript(index: Int) -> Plist {
        switch self {
        case let .Array(array):
            if index >= 0 && index < array.count {
                return Plist.wrap(array[index])
            }
            return .none

        default:
            return .none
        }
    }

}


// MARK:- Value extraction

extension Plist {

    public var string: String?       { return cast() }
    public var int: Int?             { return cast() }
    public var double: Double?       { return cast() }
    public var float: Float?         { return cast() }
    public var date: Date?         { return cast() }
    public var data: Data?         { return cast() }
    public var number: NSNumber?     { return cast() }
    public var bool: Bool?           { return cast() }


    // unwraps and returns the underlying value
    public var value: Any? {
        switch self {
        case let .Value(value):
            return value
        case let .dictionary(dict):
            return dict
        case let .Array(array):
            return array
        case .none:
            return nil
        }
    }

    // returns the underlying array
    public var array: NSArray? {
        switch self {
        case let .Array(array):
            return array
        default:
            return nil
        }
    }

    // returns the underlying dictionary
    public var dict: NSDictionary? {
        switch self {
        case let .dictionary(dict):
            return dict
        default:
            return nil
        }
    }

}


// MARK:- CustomStringConvertible

extension Plist : CustomStringConvertible {
    public var description:String {
        switch self {
        case let .Array(array): return "(array \(array))"
        case let .dictionary(dict): return "(dict \(dict))"
        case let .Value(value): return "(value \(value))"
        case .none: return "(none)"
        }
    }
}

Swift 3.0斯威夫特 3.0

if you want to read a "2-dimensional Array" from .plist, you can try it like this:如果你想从 .plist 读取一个“二维数组”,你可以这样尝试:

if let path = Bundle.main.path(forResource: "Info", ofType: "plist") {
    if let dimension1 = NSDictionary(contentsOfFile: path) {
        if let dimension2 = dimension1["key"] as? [String] {
            destination_array = dimension2
        }
    }
}

如果您有 Info.plist,则使用

Bundle.main.infoDictionary

Simple struct to access plist file (Swift 2.0)访问 plist 文件的简单结构(Swift 2.0)

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

  static let someValue = dict["someKey"] as! String
}

Usage:用法:

print("someValue = \(Configuration.someValue)")

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM