Ошибка (“'()' не идентична 'UInt8'”) при записи байтов NSData в NSOutputStream с использованием функции записи в Swift
Вопрос
Я пытаюсь создать асинхронную загрузку файлов в Swift на основе Метод Эрики Садун.Но мне это нужно для обработки больших файлов, поэтому я нашел этот ответ об использовании NSOutputStream вместо NSData, имеет смысл.
Однако я не могу заставить это сработать.Я получаю эту ошибку, когда пытаюсь добавить байты NSData (в моей функции NSURLConnection didReceiveData) в функцию записи NSOutputStream: '()' is not identical to 'UInt8'
в этом ряду: bytesWritten = self.downloadStream.write(data.bytes, maxLength: bytesLeftToWrite)
.
data.bytes
относится к тому типу ConstUnsafePointer<()>
и тот .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
больше не гарантирует, что базовые данные будут храниться в одном непрерывном блоке памяти.Например, согласно документации для didReceiveData
из числа NSURLSessionDataDelegate
протокол:
Потому что
NSData
объект часто составляется из нескольких различных объектов данных, по возможности используйтеNSData
’senumerateByteRangesUsingBlock:
метод для перебора данных вместо использования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 (и связанного с ним компилятора) использовали более неудобную конструкцию для обновления логической ссылки, чтобы остановить перечисление.