Error (“'()' is not identical to 'UInt8'”) writing NSData bytes to NSOutputStream using the write function in Swift

前端 未结 2 1251
一个人的身影
一个人的身影 2020-12-19 22:46

I\'m trying to build an asynchronous file download in Swift based on the Erica Sadun\'s method. But I need it to handle bigger files, so I found this answer about using a NS

相关标签:
2条回答
  • 2020-12-19 23:07

    I'd would suggest availing yourself of enumerateByteRangesUsingBlock, because NSData no longer guarantees that the underlying data will be held in a single contiguous memory block. For example, according to the documentation for didReceiveData of the NSURLSessionDataDelegate protocol:

    Because the NSData object is often pieced together from a number of different data objects, whenever possible, use NSData’s enumerateByteRangesUsingBlock: method to iterate through the data rather than using the bytes method (which flattens the NSData object into a single memory block).

    Thus, for example, you could do an extension of NSOutputStream that writes the contents of a 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
        }
    
    }
    

    Note, the technique of stopping the enumeration in case of error, namely stop.initialize(true), requires Xcode 6 beta 4 or later. Earlier versions of Xcode (and associated compiler) used a more awkward construction for updating the boolean reference to stop the enumeration.

    0 讨论(0)
  • 2020-12-19 23:09

    You can cast the pointer with UnsafePointer():

    bytesWritten = self.downloadStream.write(UnsafePointer(data.bytes), maxLength: bytesLeftToWrite)
    

    There is also a problem in your write loop, because you always write the initial bytes of the data object to the output stream.

    It should probably look similar to this (untested):

    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
    
        // ...
    }
    
    0 讨论(0)
提交回复
热议问题