我的 iOS 应用程序从后端获取压缩数据,然后将其解压缩为人类可读的字符串。这是我用来解压的函数:
import Compression
func decompress(_ data: Data) -> String? {
guard let string = String(data: data, encoding: .utf8),
let data = Data(base64Encoded: string)
else { return nil }
let headerSize = 2
let size = compression_decode_scratch_buffer_size(COMPRESSION_ZLIB)
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
defer { buffer.deallocate() }
let result = data.subdata(in: headerSize..<data.count).withUnsafeBytes {
guard let baseAddress = $0.baseAddress else {
return ""
}
let decompressedSize = compression_decode_buffer(
buffer,
size,
baseAddress.bindMemory(to: UInt8.self, capacity: 1),
data.count - headerSize,
nil,
COMPRESSION_ZLIB
)
guard decompressedSize > 0 else {
return ""
}
return String(
decoding: Data(bytes: buffer, count: decompressedSize),
as: UTF8.self
)
} as String
guard !result.isEmpty else {
return nil
}
return result
}
我需要一个反向函数,它返回给定未压缩字符串的压缩数据:
func compress(_ string: String) -> Data?
我正在努力实施。这是我试过的:
import Compression
func compress(_ string: String) -> Data? {
guard let data = string.data(using: .utf8) else {
return nil
}
let bufferSize = data.count + data.count / 2 + 12
var buffer = [UInt8](repeating: 0, count: bufferSize)
let compressedSize = data.withUnsafeBytes {
guard let baseAddress = $0.baseAddress else {
return 0
}
return compression_encode_buffer(
&buffer,
buffer.count,
baseAddress.assumingMemoryBound(to: UInt8.self),
data.count,
nil,
COMPRESSION_ZLIB
)
}
guard compressedSize > 0 else {
return nil
}
return Data(bytes: buffer, count: compressedSize)
}
虽然它确实压缩了字符串,但它不是我使用的
decompress
函数的反向操作:
let string = "Hello, World!"
let compressedData = compress(string)! // Data(74 bytes)
let decompressedString = decompress(compressedData) // nil
根据后端返回的数据,
decompress
函数被证明可以正常工作。我正在使用 Swift 5.8 并以 iOS 16 为目标。
提前感谢您的任何提示和建议。
排查问题后,我想到可以简化功能。我可以删除 base64 字符串转换并仅对原始
Data
类型进行操作。
我让它与以下实现一起工作:
import Foundation
import Compression
func compress(_ data: Data) -> Data? {
var buffer = [UInt8](
repeating: 0,
count: compression_encode_scratch_buffer_size(COMPRESSION_ZLIB)
)
let compressedSize = data.withUnsafeBytes {
guard let baseAddress = $0.baseAddress else {
return 0
}
return compression_encode_buffer(
&buffer,
buffer.count,
baseAddress.assumingMemoryBound(to: UInt8.self),
data.count,
nil,
COMPRESSION_ZLIB
)
}
guard compressedSize > 0 else {
return nil
}
return Data(bytes: buffer, count: compressedSize)
}
func decompress(_ data: Data) -> Data? {
let headerSize = 0
var buffer = [UInt8](
repeating: 0,
count: compression_decode_scratch_buffer_size(COMPRESSION_ZLIB)
)
let subdata = data.subdata(in: headerSize..<data.count)
let decompressedSize = subdata.withUnsafeBytes { sourcePtr in
guard let baseAddress = sourcePtr.baseAddress else {
return 0
}
return compression_decode_buffer(
&buffer,
buffer.count,
baseAddress.assumingMemoryBound(to: UInt8.self),
subdata.count,
nil,
COMPRESSION_ZLIB
)
}
guard decompressedSize > 0 else {
return nil
}
return Data(bytes: buffer, count: decompressedSize)
}
适用于以下示例:
let string = "Hello, World!"
let compressed = compress(string.data(using: .utf8)!)!
let decompressed = decompress(compressed)!
let decompressedString = String(data: decompressed, encoding: .utf8)
decompressedString == string // ✅ true
但是,这不适用于后端返回给我的数据。为了让它工作,我需要在
headerSize
函数中将2
值更改为decompress
。当我这样做时,我可以从后端解压数据,但我的compress
功能不再正常工作。我真的不明白标题大小是多少,以及如何更新compress
函数,因此它与我的decompress
函数对称,headerSize
等于2
.