将数组内容(自定义类型)写入 plist 作为 swift 中的键控数组

Posted

技术标签:

【中文标题】将数组内容(自定义类型)写入 plist 作为 swift 中的键控数组【英文标题】:Write array content (of custom type) to plist as keyed array in swift 【发布时间】:2019-05-12 18:15:36 【问题描述】:

MacOS、斯威夫特 4。

我想将数据存储在 plist 中。我可以加载这些值,但是在写出它们时它们的格式不正确。

我正在加载 plist(在表格视图中显示它),效果很好:

    func loadBooks() 
        let path = dataFilePath() // /com.name.books/Data/Documents/

        do 
            let data = try Data(contentsOf: path)
            let decoder = PropertyListDecoder()
            let plist = try decoder.decode([String: [Book]].self, from: data)
            books = plist["BooksData"]!
         catch 
            print("Error occurred: \(error.localizedDescription)")
        
    

这是我正在加载的 plist:

<plist version="1.0">
    <dict>
    <key>BooksData</key>
    <array>
        <dict>
            <key>author</key>
            <string>First Author</string>
            <key>title</key>
            <string>First Title</string>     
            <key>lentBy</key>
            <string>Person</string>
        </dict>       
        <dict>
            <key>author</key>
            <string>Second Author</string>  
            <key>title</key>
            <string>Book Title2</string>
            <key>lentBy</key>
            <string>Another Person</string>
        </dict>
    </array>  
    </dict>
</plist>

我正在尝试将数组写回 plist,如下所示:

  func saveBooks() 
        let data = books

        do 
            let encoder = PropertyListEncoder()
            var plist = try encoder.encode(data)
            try plist.write(to: dataFilePath())
         catch 
            print("Error occured: \(error.localizedDescription)")
        
    

plist 内容失去其“包装”和密钥(“BooksData”),随后无法再使用 loadBooks() 函数读取。

这是输出:

<plist version="1.0">
    <array>    
        <dict>
            <key>author</key>
            <string>First Author</string>
            <key>title</key>
            <string>First Title</string>     
            <key>lentBy</key>
            <string>Person</string>
        </dict>       
        <dict>
            <key>author</key>
            <string>Second Author</string>  
            <key>title</key>
            <string>Book Title2</string>
            <key>lentBy</key>
            <string>Another Person</string>
        </dict>  
    </array>
</plist>

我玩过NSMutableDictionary(),尝试用dict.setObject(plist, forKey: "BooksData") 重新包装它并用dict.write(toFile: dataFilePath().absoluteString, atomically: true) 编写它。

            let encoder = PropertyListEncoder()
            var plist = try encoder.encode(data)

            dict.setObject(plist, forKey: "BooksData" as NSCopying)
            dict.write(toFile: dataFilePath().absoluteString, atomically: true)
            print(dict)

打印字典返回


    BooksData = <62706c69 73743030 a401080c 10d30203 04050607 55746974 6c655661 7574686f 72566c65 6e744279 59427563 68746974 656c5b46 696e6b2c 20457567 656e546e 6f6e65d3 02030409 0a0b5f10 14457266 61687275 6e672075 6e642055 72746569 6c5f100f 48757373 65726c2c 2045646d 756e645a 50617472 69636b20 5379d302 03040d0e 0f5f101a 4b726974 696b2064 65722072 65696e65 6e205665 726e756e 66745e4b 616e742c 20496d6d 616e7565 6c50d302 03041112 0f5b4369 74612041 63746976 615e4172 656e6474 2c204861 6e6e6168 080d141a 2128323e 434a6173 7e85a2b1 b2b9c500 00000000 00010100 00000000 00001300 00000000 00000000 00000000 0000d4>;

文件甚至没有被写出,即 dataFilePath() 处的旧文件保持不变。

答案会在PropertyListSerialization.propertyList(from:options:format:) 中吗?还是CodingKeys?还是encode(title, forKey:"BooksData")(?) 等? NSMutableArray? KeyedDecodingContainerunkeyedContainer 等等? NSKeyedArchiver?

这似乎是一个如此简单的任务,但我就是做错了。周围似乎有一些相关的线索,但没有真正适用或给我解决这个问题的关键信息。该文档对我也没有任何说明,我需要一些具体的指针。

请帮忙。

【问题讨论】:

【参考方案1】:

由于预期类型是[String: [Book]],您必须手动创建根字典

func saveBooks() 
    do 
        let encoder = PropertyListEncoder()
        let plistData = try encoder.encode(["BooksData":books])
        try plistData.write(to: dataFilePath())
     catch 
        print("Error occured:", error) // never ever print `localizedDescription`
    

但如果 plist 仅包含 books 数组,则仅加载并保存数组。此外,我建议将可能的错误交给调用者

var books = [Book]()

func loadBooks() throws 
    let path = dataFilePath() // /com.name.books/Data/Documents/
    let data = try Data(contentsOf: path)
    let decoder = PropertyListDecoder()
    books = try decoder.decode([Book].self, from: data)

那么save方法匹配类型

func saveBooks() throws 
    let encoder = PropertyListEncoder()
    let plistData = try encoder.encode(books)
    try plistData.write(to: dataFilePath())

【讨论】:

天哪,谢谢!另外对于建议,我会尝试一下。打印“localizedDescription”有什么问题? 结合Codable localizedDescription 打印一个通用的无意义的错误消息。只有完整的error 包含有关Codable 错误的详细描述。

以上是关于将数组内容(自定义类型)写入 plist 作为 swift 中的键控数组的主要内容,如果未能解决你的问题,请参考以下文章

将数据写入 .plist

将文本文件内容写入 Java 中的自定义数组列表

将项目添加到 .plist 并在自定义 UITableViewCell 中显示

将嵌套字典写入 plist (Swift) 时的类型问题

如何将自定义类型的列表/数组写入 HDF5 文件?

将数据附加到 PLIST - iPhone