我在玩苹果的新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*类仍然有效,可以使用吗?
如果我想将.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
}
}
为Swift 2.0编辑:
if let path = NSBundle.mainBundle().pathForResource("Config", ofType: "plist"), dict = NSDictionary(contentsOfFile: path) as? [String: AnyObject] {
// use swift dictionary as normal
}
为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
}
我已经创建了一个简单的字典初始化器替换NSDictionary(contentsOfFile: path)。只要去掉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
}
}
你可以这样使用它:
let filePath = Bundle.main.path(forResource: "Preferences", ofType: "plist")!
let preferences = Dictionary(contentsOfFile: filePath)!
UserDefaults.standard.register(defaults: preferences)
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")
}
}
斯威夫特5
如果你想获取某个键的特定值,那么我们可以使用下面的扩展,它使用Bundle上的infoDictionary属性。
可以使用Bundle.main.infoDictionary获取所有信息。在表单字典中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
}
}
使用
guard let apiURL = Bundle.infoPlistValue(forKey: "API_URL_KEY") as? String else { return }
斯威夫特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中使用nsdictionary:
Swift 4
var nsDictionary: NSDictionary?
if let path = Bundle.main.path(forResource: "Config", ofType: "plist") {
nsDictionary = NSDictionary(contentsOfFile: path)
}
Swift 3+
if let path = Bundle.main.path(forResource: "Config", ofType: "plist"),
let myDict = NSDictionary(contentsOfFile: path){
// Use your myDict here
}
以及旧版本的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
}
NSClasses仍然可用,完全可以在Swift中使用。我想他们可能很快就会把重点转移到swift上,但是目前swift api并没有核心NSClasses的所有功能。