【问题标题】:Sometimes methods fails with Fatal error: UnsafeMutablePointer.initialize overlapping range有时方法会因致命错误而失败:UnsafeMutablePointer.initialize 重叠范围
【发布时间】:2020-03-18 19:56:49
【问题描述】:

我有以下代码在 Swift 5 中将一些 Data 解压缩回 String。该方法大部分工作正常,但有时会失败并显示以下错误消息:

Thread 1: Fatal error: UnsafeMutablePointer.initialize overlapping range

extension Data
{
    func decompress(destinationSize: Int) -> String?
    {
        let destinationBuffer = UnsafeMutablePointer<UInt8>.allocate(capacity: destinationSize)

        let decodedString = self.withUnsafeBytes
        {
            unsafeRawBufferPointer -> String? in

            let unsafeBufferPointer = unsafeRawBufferPointer.bindMemory(to: UInt8.self)
            if let unsafePointer = unsafeBufferPointer.baseAddress
            {
                let decompressedSize = compression_decode_buffer(destinationBuffer, destinationSize, unsafePointer, self.count, nil, COMPRESSION_ZLIB)

                if decompressedSize == 0
                {
                    return String.empty
                }

                let string = String(cString: destinationBuffer)
                let substring = string.substring(0, decompressedSize)

                return substring
            }

            return nil
        }

        return decodedString
    }
}

错误发生在以下行:

let string = String(cString: destinationBuffer)

有人能解释一下为什么这(有时)会失败吗?

【问题讨论】:

  • 这只是一个学术练习,还是有理由不能只使用String(data: encoding:)
  • 使用这种方法只会给我压缩数据的字符串表示形式。我正在尝试获取解压缩数据的字符串。
  • 我不明白区别。上述方法将解码最初编码为Data 的字符串。你想用你的方法从Data 中得到什么?
  • 我的原始字符串是由 GPS 坐标创建的折线。我正在将此折线字符串编码为将存储在 Firestore 中的 Data 对象。现在我正试图从我的解码数据中取回那个字符串。我有解码数据和原始大小(所以我可以分配一个可以保存原始字符串的数组)。
  • 我也有同样的问题,你有没有找到好的解释?

标签: swift unsafemutablepointer


【解决方案1】:

我已切换到以下代码,现在一切正常(Swift 5):

import Compression

extension Data
{
    func compress() -> Data?
    {
        return self.withUnsafeBytes
        {
            dataBytes in

            let sourcePtr: UnsafePointer<UInt8> = dataBytes.baseAddress!.assumingMemoryBound(to: UInt8.self)

            return self.perform(operation: COMPRESSION_STREAM_ENCODE, source: sourcePtr, sourceSize: self.count)
        }
    }

    func decompress() -> Data?
    {
        return self.withUnsafeBytes
        {
            unsafeRawBufferPointer -> Data? in

            let unsafeBufferPointer = unsafeRawBufferPointer.bindMemory(to: UInt8.self)
            if let unsafePointer = unsafeBufferPointer.baseAddress
            {
                return self.perform(operation: COMPRESSION_STREAM_DECODE, source: unsafePointer, sourceSize: self.count)
            }

            return nil
        }
    }

    fileprivate func perform(operation: compression_stream_operation, source: UnsafePointer<UInt8>, sourceSize: Int, preload: Data = Data()) -> Data?
    {
        guard sourceSize > 0 else { return nil }

        let streamBase = UnsafeMutablePointer<compression_stream>.allocate(capacity: 1)
        defer { streamBase.deallocate() }
        var stream = streamBase.pointee

        let status = compression_stream_init(&stream, operation, COMPRESSION_ZLIB)
        guard status != COMPRESSION_STATUS_ERROR else { return nil }
        defer { compression_stream_destroy(&stream) }

        var result = preload
        var flags: Int32 = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
        let blockLimit = 64 * 1024
        var bufferSize = Swift.max(sourceSize, 64)

        if sourceSize > blockLimit
        {
            bufferSize = blockLimit
        }

        let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
        defer { buffer.deallocate() }

        stream.dst_ptr  = buffer
        stream.dst_size = bufferSize
        stream.src_ptr  = source
        stream.src_size = sourceSize

        while true
        {
            switch compression_stream_process(&stream, flags)
            {
                case COMPRESSION_STATUS_OK:
                    guard stream.dst_size == 0 else { return nil }
                    result.append(buffer, count: stream.dst_ptr - buffer)
                    stream.dst_ptr = buffer
                    stream.dst_size = bufferSize

                    if flags == 0 && stream.src_size == 0
                    {
                        flags = Int32(COMPRESSION_STREAM_FINALIZE.rawValue)
                    }

                case COMPRESSION_STATUS_END:
                    result.append(buffer, count: stream.dst_ptr - buffer)
                    return result

                default:
                    return nil
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-06-18
    • 1970-01-01
    • 2017-07-28
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    相关资源
    最近更新 更多