使用 Swift 中的写入函数将 NSData 字节写入 NSOutputStream 时出错 ("'()' is not identical to 'UInt8'"



我正在尝试基于Erica Sadun的方法在Swift中构建异步文件下载。但是我需要它来处理更大的文件,所以我发现这个关于使用NSOutputStream而不是NSData的答案是有意义的。

然而,我不能让它工作。当我尝试将NSData字节(在我的NSURLConnection didReceiveData函数中)添加到NSOutputStream写函数时,我得到了这个错误:'()' is not identical to 'UInt8'在这一行:bytesWritten = self.downloadStream.write(data.bytes, maxLength: bytesLeftToWrite)

data.bytesConstUnsafePointer<()>类型,而.write()函数期望该类型为ConstUnsafePointer<UInt8>,因此在这种意义上,错误是完全有意义的。但由于我是iOS新手,当然还有Swift编程新手,我不知道如何解决这个问题。

那么,我如何将data.bytes: ConstUnsafePointer<()>转换为ConstUnsafePointer<UInt8>,使其以其他方式工作?

我的didReceiveData函数:

func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
    var bytesLeftToWrite: NSInteger = data.length
    var bytesWritten: NSInteger = 0
    while bytesLeftToWrite > 0 {
        bytesWritten = self.downloadStream.write(data.bytes, maxLength: bytesLeftToWrite)
        if bytesWritten == -1 {
            break
        }
        bytesLeftToWrite -= bytesWritten
        let responseExpectedlenght: NSNumber = NSNumber(longLong: self.downloadResponse!.expectedContentLength)
        let dataLength: NSNumber = NSNumber(long: data.length)
        self.downloadProgressPercentage = ((dataLength / responseExpectedlenght) * 100)
        println("Downloaded: (self.downloadProgressPercentage)%")
    }
}

可以使用UnsafePointer():

强制转换指针
bytesWritten = self.downloadStream.write(UnsafePointer(data.bytes), maxLength: bytesLeftToWrite)

在写循环中也有一个问题,因为您总是写初始字节的数据对象到输出流。

它应该看起来像这样(未经测试):

var bytes = UnsafePointer<UInt8>(data.bytes)
var bytesLeftToWrite: NSInteger = data.length
while bytesLeftToWrite > 0 {
    let bytesWritten = self.downloadStream.write(bytes, maxLength: bytesLeftToWrite)
    if bytesWritten == -1 {
        break // Some error occurred ...
    }
    bytesLeftToWrite -= bytesWritten
    bytes += bytesWritten // advance pointer
    // ...
}

我建议您使用enumerateByteRangesUsingBlock,因为NSData不再保证底层数据将保存在单个连续内存块中。例如,根据NSURLSessionDataDelegate协议的didReceiveData的文档:

因为NSData对象通常是由许多不同的数据对象拼凑在一起的,所以只要可能,使用NSDataenumerateByteRangesUsingBlock:方法来迭代数据,而不是使用bytes方法(它将NSData对象平铺成单个内存块)。

因此,例如,您可以对NSOutputStream进行扩展,写入NSData的内容:
extension NSOutputStream {
    /// Write contents of NSData to `NSOutputStream`
    ///
    /// - parameter data:   The `NSData` being written to the stream.
    ///
    /// - returns:          The number of bytes written. In case of error, returns -1.
    func writeData(data: NSData) -> Int {
        var totalBytesWritten = 0
        data.enumerateByteRangesUsingBlock() {
            buffer, range, stop in
            var bytes = UnsafePointer<UInt8>(buffer)
            var bytesWritten = 0
            var bytesLeftToWrite = range.length
            while bytesLeftToWrite > 0 {
                bytesWritten = self.write(bytes, maxLength: bytesLeftToWrite)
                if bytesWritten < 0 {
                    stop.initialize(true)
                    totalBytesWritten = -1
                    return
                }
                bytes += bytesWritten
                bytesLeftToWrite -= bytesWritten
                totalBytesWritten += bytesWritten
            }
        }
        return totalBytesWritten
    }
}

注意,在发生错误时停止枚举的技术,即stop.initialize(true),需要Xcode 6 beta 4或更高版本。早期版本的Xcode(和相关的编译器)使用了一种更尴尬的结构来更新布尔引用以停止枚举。

最新更新