我在玩苹果的新Swift编程语言,遇到了一些问题…

目前我试图读取一个plist文件,在Objective-C中,我会做以下工作来获取内容作为NSDictionary:

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

我如何得到一个plist作为一个字典在Swift?

我假设我可以得到路径到plist:

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

当这工作(如果它是正确的?):我如何获得内容作为一个字典?

还有一个更普遍的问题:

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


当前回答

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

阅读更多 如何在swift中使用属性列表(. plist)。

其他回答

如果你有信息。Plist,然后使用

Bundle.main.infoDictionary

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

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

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

斯威夫特4.0

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

首先将结构设置为.plist文件的格式。对于这个例子,我将考虑一个根级字典和3个条目:1个字符串键“name”,1个Int键“age”,1个布尔键“single”。下面是结构体:

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

    let name: String
    let age: Int
    let single: Bool
}

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

不用担心太多代码,而且都在Swift中。更好的是,我们现在有一个Config结构的实例化,我们可以很容易地使用:

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

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

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

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

正如你所看到的,我正在使用字符串数组:字符串字典来存储网站名称及其对应的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)

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

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

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

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