Erro ("'()' não é idêntico ao 'UInt8'") escrita NSData bytes para NSOutputStream usando a função de escrita Rápida
Pergunta
Eu estou tentando construir um assíncrona download de arquivo no Swift com base no Erica Sadun do método.Mas eu preciso dele para lidar com arquivos maiores, então eu encontrei esta resposta sobre o uso de um NSOutputStream em vez de NSData, faz sentido.
No entanto, eu não posso fazê-lo funcionar.Eu recebo este erro quando eu tento adicionar NSData bytes (no meu NSURLConnection didReceiveData função) para o NSOutputStream de escrever a função: '()' is not identical to 'UInt8'
por esta linha: bytesWritten = self.downloadStream.write(data.bytes, maxLength: bytesLeftToWrite)
.
data.bytes
é do tipo ConstUnsafePointer<()>
e o .write()
função espera que o tipo a ser ConstUnsafePointer<UInt8>
, então, nesse sentido, o erro faz perfeito sentido.Mas desde que eu sou novo para o iOS e, claro, Swift programação, eu não posso colocar minha cabeça em torno de como consertar isso.
Então, como faço para converter o data.bytes: ConstUnsafePointer<()>
para ConstUnsafePointer<UInt8>
alt.fazer este trabalho de alguma outra forma?
Meu didReceiveData
função:
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)%")
}
}
Solução
Você pode converter o ponteiro com UnsafePointer()
:
bytesWritten = self.downloadStream.write(UnsafePointer(data.bytes), maxLength: bytesLeftToWrite)
Há também um problema em sua gravação de loop, porque você sempre escrever o inicial bytes do objeto de dados para o fluxo de saída.
Ele provavelmente deve parecer semelhante a este (não testado):
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
// ...
}
Outras dicas
Eu gostaria de sugerir valendo-se de enumerateByteRangesUsingBlock
, porque NSData
já não garante que a base de dados será realizada em um único bloco de memória contígua.Por exemplo, de acordo com a documentação didReceiveData
do NSURLSessionDataDelegate
protocolo:
Porque o
NSData
objeto geralmente é reunido a partir de um número de diferentes objetos de dados, sempre que possível, useNSData
'senumerateByteRangesUsingBlock:
método para iterar através de dados em vez de utilizar obytes
método (o que achata aNSData
objeto em um único bloco de memória).
Assim, por exemplo, você poderia fazer uma extensão de NSOutputStream
que escreve o conteúdo de uma 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
}
}
Observação, a técnica de parar a enumeração, em caso de erro, a saber, stop.initialize(true)
, requer Xcode 6 beta 4 ou posterior.Versões anteriores do Xcode (e associados do compilador), usou um mais estranho de construção para atualizar o valor booleano de referência para parar a enumeração.