Декодировать PropertyList с помощью Swift 4 Codable PropertyListDecoder()

Я пытаюсь декодировать plist, используя PropertyListDecoder(), но когда я пытаюсь получить доступ к ключам, я получаю сообщение об ошибке, в котором говорится, что это неправильный формат. Я в недоумении, что я делаю неправильно. Я предполагаю, что могу декодировать файл Plist так же, как я могу декодировать файл JSON, верно? Не знаю, я еще новичок в этом.

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

Это был мой первый подход к этому, но он выдавал ошибку, говорящую

«Не удалось прочитать данные, потому что они были в неправильном формате»

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

Второй подход, как бы просто забросил Codable все вместе, все равно не смог вытащить значения

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

Файл plist структурирован как

<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>

Любой совет?


person SirCJ    schedule 02.08.2017    source источник
comment
Я не знаю, есть ли он в plist, или вы пропустили здесь закрывающий дикт при вставке   -  person Sourav Sachdeva    schedule 02.08.2017
comment
Это недопустимый plist. Вы можете отредактировать это? трудно получить структуру plist-файла, когда все в порядке. Также добавьте определение вашего класса/структуры AccessControl   -  person Code Different    schedule 02.08.2017
comment
Я обновил пост.   -  person SirCJ    schedule 03.08.2017


Ответы (1)


Ваш файл plist был плохо отформатирован и, следовательно, не поддавался расшифровке. Вы не должны называть каждый ключ другим именем ключа, таким как KEY1, KEY2, KEY3 и т. д. Вместо этого вы должны использовать одно имя для ключа key и указать фактическое имя в поле значения. То же самое касается secret.

Вот лучший файл 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: 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"
    }
}
person Code Different    schedule 19.08.2017
comment
Мне удалось протестировать правильно отформатированный Plist. Я попытался переписать его. Это не сработало, но ваше решение сработало. Моя модель Swift не была правильно настроена для получения декодированного Plist. - person SirCJ; 21.08.2017