首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ZIPFoundation:编写大型PNG以通过数据提供程序存档的问题

ZIPFoundation:编写大型PNG以通过数据提供程序存档的问题
EN

Stack Overflow用户
提问于 2018-05-01 21:46:09
回答 2查看 308关注 0票数 3

更新:我可以通过将PNG大小设置为大于任意值(即700 x 700 pt失败)来再现这个值。在任意值下写入和读取很好。我不确定那条线到底在哪。

我使用zip存档作为我的文档文件格式。当尝试从文件浏览器页面的多个档案中读取PNG预览时,我看到了意想不到的结果。

在后台查询文档URL,然后创建一个文件数据对象。查询完成后,在主线程上调用UI更新,文件数据对象充当集合视图的数据提供程序。

PNG被序列化为如下数据:

代码语言:javascript
复制
let imageData = UIImagePNGRepresentation(image)

当读取数据时,相关条目被提取到内存中,然后反序列化到它们各自的对象中。

我看到的是文档缩略图只是间歇地显示。对于后台操作,ZIPFoundation是否可能不是线程安全的?

我在一个简单的测试项目中模拟了这一点,它运行得很好,但我没有阅读多个文档,也没有在后台调用它。我是不是做错了什么(下面的代码)?

使用者闭包是否使用自己的线程(也许我正在返回数据,然后才能完成)?

代码语言:javascript
复制
do {
    let decoder = JSONDecoder()
    let archive = Archive(url: URL, accessMode: .read)

    // Metadata
    if let metadataData = try archive?.readData(named: Document.MetadataFilename) {
        self.metadata = try decoder.decode(Metadata.self, from: metadataData)
    } else {
        logDebug(self, "metadata not read")
    }

    // Preview
    if let previewData = try archive?.readData(named: Document.PreviewFilename) {
        if let image = UIImage(data: previewData) {
            self.image = image
            return
        }
    } else {
        logDebug(self, "image not read")
    }

} catch {
    logError(self, "Loading of FileWrapper failed with error: \(error.localizedDescription)")
}

// Failure fall through
// Mark this as failed by using the x image
self.image = UIImage(named: "unavailable")
}

为了方便起见,我把分机转到档案馆:

代码语言:javascript
复制
/// Associates optional data with entry name
struct NamedData {
    let name : String
    let data : Data?
}

// MARK: - Private
extension Archive {

    private func addData(_ entry: NamedData) throws {
        let archive = self
        let name = entry.name
        let data = entry.data
        do {
            if let data = data {
                try archive.addEntry(with: name, type: .file, uncompressedSize: UInt32(data.count), compressionMethod: .none, provider: { (position, size) -> Data in
                    return data
                })
            }
        } catch {
            throw error
        }
    }

    private func removeData(_ entry: NamedData) throws {
        let archive = self
        let name = entry.name
        do {
            if let entry = archive[name] { try archive.remove(entry) }
        } catch {
            throw error
        }
    }
}

// MARK: - Public
extension Archive {

    /// Update NamedData entries in the archive
    func updateData(entries: [NamedData]) throws {
        // Walk each entry and overwrite
        do {
            for entry in entries {
                try removeData(entry)
                try addData(entry)
            }
        } catch {
            throw error
        }
    }

    /// Add NamedData entries to the archive (updateData is the preferred
    /// method since no harm comes from removing entries before adding them)
    func addData(entries: [NamedData]) throws {
        // Walk each entry and create
        do {
            for entry in entries {
                try addData(entry)
            }
        } catch {
            throw error
        }
    }

    /// Read Data out of the entry using its name
    func readData(named name: String) throws -> Data? {
        let archive = self
        // Get data from entry
        do {
            var entryData : Data? = nil
            if let entry = archive[name] {
                // _ = returned checksum
                let _ = try archive.extract(entry, consumer: { (data) in
                    entryData = data
                })
            }
            return entryData
        } catch {
            throw error
        }
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-05-02 20:12:26

ZIPFoundation中基于闭包的API旨在提供/使用按块划分的数据。根据数据的最终大小和配置的块大小(可选参数,默认值为16*1024),提供者/使用者闭包可以被多次调用。

当您正在提取一个条目时

代码语言:javascript
复制
let _ = try archive.extract(entry, consumer: { (data) in
    entryData = data
})

您总是使用由entryData闭包提供的最新块覆盖consumer (如果最终大小大于块大小)。

相反,您可以使用

代码语言:javascript
复制
var entryData = Data()
let _ = try archive.extract(entry, consumer: { (data) in
    entryData.append(data)
})

以确保在entryData对象中累积整个条目。

在您的Provider代码中也发生了类似的事情。与其总是返回整个图像数据对象,不如在每次调用闭包时提供一个块(从positionsize开始)。

票数 3
EN

Stack Overflow用户

发布于 2020-04-21 15:19:55

我也遇到了同样的问题,下面的问题对我很有帮助:

代码语言:javascript
复制
archive.addEntry(with: "entryName",
                 type: .file,
                 uncompressedSize: dataSize,
                 compressionMethod: .none,
                 provider: { (position, size) in
                     return data.subdata(in: (position ..< position + size))})
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50124304

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档