[英]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) 。
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。
//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 类型组合。
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.就我而言,我创建了一个名为
appSettings
的NSDictionary
并添加了所有需要的键。 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
类型设置为AnyObject
以AnyObject
有关可能发生的意外推断的警告。
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)"
}
}
}
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.