且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

使用Swift 4 Codable PropertyListDecoder()解码PropertyList

更新时间:2022-10-14 22:39:01

您的plist文件格式错误,因此无法解码。您不应该用不同的键名来命名每个键,例如 KEY1 KEY2 KEY3 等。相反,您应该对键 key 使用一个名称,并将实际名称放在值字段中。 秘密也是如此。



这里是一个更好的plist文件:

 <?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>
< dict>
< key> A_GROUP_OF_KEYS< / key>
< array>
< dict>
< key> key< / key>
< string> KEY1_STRING< / string>
< key> secret< / key>
< string> SECRET1_STRING< / string>
< / dict>
< dict>
< key> key< / key>
< string> KEY2_STRING< / string>
< key> secret< / key>
< string> SECRET2_VALUE< / string>
< / dict>
< dict>
< key> key< / key>
< string> KEY3_STRING< / string>
< key> secret< / key>
< string> SECRET3_VALUE< / string>
< / dict>
< / array>
< key> ANOTHER_GROUP_OF_KEYS< / key>
< array>
< dict>
< key> key< / key>
< string> KEY1_STRING< / string>
< key> secret< / key>
< string> SECRET1_STRING< / string>
< / dict>
< dict>
< key> key< / key>
< string> KEY2_STRING< / string>
< key> secret< / key>
< string> SECRET2_VALUE< / string>
< / dict>
< dict>
< key> key< / key>
< string> KEY3_STRING< / string>
< key> secret< / key>
< string> SECRET3_VALUE< / string>
< / dict>
< / array>
< / dict>
< / plist>

解码非常简单:

  struct AccessControl:可解码{
struct密钥:可解码{
var键:String
var secret:String
}

var keyGroup1:[密钥]
var keyGroup2:[密钥]

枚举CodingKeys:字符串,CodingKey {
case keyGroup1 = A_GROUP_OF_KEYS
case keyGroup2 = ANOTHER_GROUP_OF_KEYS
}
}


Im trying to decode a plist using PropertyListDecoder() but when I get to the trying to access the keys, I get an error that says it's in the wrong format. I'm at a loss on what I'm doing wrong. Im under the assumption I can decode a Plist file the same way I can decode a JSON file right? I don't know, I'm still new to this.

//struct for PLists
struct AccessControl: Decodable {
    enum AccessControlKeys: String, CodingKey {
         case api
     }

    enum KeySecretKeys: String, CodingKey {
        case apiKey = "KEY"
        case apiSecret = "SECRET"
    }

    var KEYS: [KeySecrets]
//custom decoder
    init(from decoder: Decoder) throws {
        let accessContainer = try decoder.container(keyedBy: AccessControlKeys.self)
        let nestedContainer = try accessContainer.nestedContainer(keyedBy: KeySecretKeys.self, forKey: .api)
        self.KEYS = try nestedContainer([KeySecrets].self, forKey: .apiKey)
        self.KEYS = try nestedContainer.decode([KeySecrets].self, forKey: .apiSecret)
    }
}

struct KeySecrets: Decodable {
    var apiKey: String
    var apiSecret: String
}



func provideAccessKeys(for api: apis = .api, mode: modes = .dev) -> keysForApi? {
    switch api {
    case .api:
        print("Api")
    }
    switch mode {
    case .dev:
        print("mode - developers")
    case .test:
        print("mode - test")
    case .prod:
        print("mode - production")
    }
}

This was my first approach at it, but it would throw an error saying

'The data couldn't be read because it was the wrong format'

if let fileURL = Bundle.main.url(forResource: "Accesscontrol",   withExtension: "plist") {
    do {
        let data = try Data.init(contentsOf: fileURL, options: .mappedIfSafe)
        let decoder = PropertyListDecoder()
        let result = try decoder.decode(AccessControl.self, from: data)

    } catch {
        print(error.localizedDescription)
    }
}

Second approach, kinda just abandoned Codable all together, still couldn't pull out the values

guard let fileUrl = Bundle.main.url(forResource: "Accesscontrol", withExtension: "plist") else {return}
let key: String
let secret: String
do {
    let data = try Data.init(contentsOf: fileUrl, options: .mappedIfSafe)
    let plist = try! PropertyListSerialization.propertyList(from:data, options: [], format: nil) as! [Any]
  print(plist)
   let dictionary = plist[api.rawValue]

} catch {
    print(error.localizedDescription)
}

The plist file is structured like

<plist version="1.0">
<dict>
    <key>A_GROUP_OF_KEYS</key>
    <array>
        <dict>
            <key>KEY1</key>
            <string>KEY1_STRING</string>
            <key>SECRET1_KEY</key>
            <string>SECRET1_STRING</string>
        </dict>
        <dict>
        <key>KEY2</key>
        <string>KEY2_STRING</string>
        <key>SECRET2_KEY</key>
        <string>SECRET2_VALUE</string>
        </dict>
        <dict>
        <key>KEY</key>
        <string>KEY_STRING</string>
        <key>SECRET_KEY</key>
        <string>SECRET_VALUE</string>
        </dict>
    </array>
<key>ANOTHER_GROUP_OF_KEYS</key>
    <array>
        <dict>
            <key>KEY1</key>
            <string>KEY1_STRING</string>
            <key>SECRET1_KEY</key>
            <string>SECRET1_STRING</string>
        </dict>
        <dict>
        <key>KEY2</key>
        <string>KEY2_STRING</string>
        <key>SECRET2_KEY</key>
        <string>SECRET2_VALUE</string>
        </dict>
        <dict>
        <key>KEY</key>
        <string>KEY_STRING</string>
        <key>SECRET_KEY</key>
        <string>SECRET_VALUE</string>
        </dict>
    </array>
</dict>
</plist>

Any advice?

Your plist file was badly formatted and hence undecodable. You shouldn't name every key with a different key name like KEY1, KEY2, KEY3, etc. Instead, you should use one name for the key key and put the actual name in the value field. The same goes for secret.

Here's a better plist file:

<?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">
<dict>
    <key>A_GROUP_OF_KEYS</key>
    <array>
        <dict>
            <key>key</key>
            <string>KEY1_STRING</string>
            <key>secret</key>
            <string>SECRET1_STRING</string>
        </dict>
        <dict>
            <key>key</key>
            <string>KEY2_STRING</string>
            <key>secret</key>
            <string>SECRET2_VALUE</string>
        </dict>
        <dict>
            <key>key</key>
            <string>KEY3_STRING</string>
            <key>secret</key>
            <string>SECRET3_VALUE</string>
        </dict>
    </array>
    <key>ANOTHER_GROUP_OF_KEYS</key>
    <array>
        <dict>
            <key>key</key>
            <string>KEY1_STRING</string>
            <key>secret</key>
            <string>SECRET1_STRING</string>
        </dict>
        <dict>
            <key>key</key>
            <string>KEY2_STRING</string>
            <key>secret</key>
            <string>SECRET2_VALUE</string>
        </dict>
        <dict>
            <key>key</key>
            <string>KEY3_STRING</string>
            <key>secret</key>
            <string>SECRET3_VALUE</string>
        </dict>
    </array>
</dict>
</plist>

Decoding this is dead simple:

struct AccessControl: Decodable {
    struct Key: Decodable {
        var key: String
        var secret: String
    }

    var keyGroup1: [Key]
    var keyGroup2: [Key]

    enum CodingKeys: String, CodingKey {
        case keyGroup1 = "A_GROUP_OF_KEYS"
        case keyGroup2 = "ANOTHER_GROUP_OF_KEYS"
    }
}