Errore ("" () '' non è identico a 'UINT8' ") Scrittura di NSData Bytes su NSoutputStream utilizzando la funzione di scrittura in Swift
Domanda
Sto cercando di costruire un download di file asincrono in SWIFT sulla base del Metodo Erica Sadun . Ma ne ho bisogno per gestire i file più grandi, così ho trovato questa risposta sull'utilizzo di un nsoutputstream invece di nsdata , ha senso. < / P >.
Tuttavia, non riesco a farlo funzionare. Ottengo questo errore quando provo ad aggiungere i byte NSDATA (nella mia funzione NsurlConnection DidRekeDatata) alla funzione di scrittura NSOUTputStream: '()' is not identical to 'UInt8'
su questa riga: bytesWritten = self.downloadStream.write(data.bytes, maxLength: bytesLeftToWrite)
.
data.bytes
è del tipo ConstUnsafePointer<()>
e la funzione .write()
si aspetta che il tipo sia generatoDicetagcode, quindi in questo senso, l'errore ha perfettamente senso. Ma dal momento che sono nuovo per iOS e ovviamente la programmazione rapida, non riesco a farti prendere la testa su come risolvere questo problema.
Quindi, come posso convertire il ConstUnsafePointer<UInt8>
in data.bytes: ConstUnsafePointer<()>
Alt. Fai questo lavoro in altro modo?
La mia funzione ConstUnsafePointer<UInt8>
:
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)%")
}
}
. Soluzione
È possibile lanciare il puntatore con UnsafePointer()
:
bytesWritten = self.downloadStream.write(UnsafePointer(data.bytes), maxLength: bytesLeftToWrite)
.
C'è anche un problema nel tuo loop di scrittura, perché scrivi sempre il Iniziali Bytes dell'oggetto dati al flusso di uscita.
Dovrebbe probabilmente sembrare simile a questo (non testato):
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
// ...
}
. Altri suggerimenti
Suggerirei di avvalersi di enumerateByteRangesUsingBlock
, poiché NSData
non garantisce più che i dati sottostanti si terranno in un unico blocco di memoria contiguo. Ad esempio, in base alla documentazione per didReceiveData
del protocollo NSURLSessionDataDelegate
:
.Poiché l'oggetto
NSData
viene spesso messo insieme da un numero di diversi oggetti di dati, quando possibile, utilizzare il metodoNSData
tagCoDetagCoDetagCoDetagCoDetaGCodeenumerateByteRangesUsingBlock:
per iterano attraverso i dati anziché utilizzare il metodobytes
(che appiatti l'oggettoNSData
in un singolo blocco di memoria).
Pertanto, ad esempio, è possibile eseguire un'estensione del NSOutputStream
che scrive il contenuto di un 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
}
}
.
Nota, la tecnica di fermare l'enumerazione in caso di errore, vale a dire stop.initialize(true)
, richiede Xcode 6 Beta 4 o successive. Le versioni precedenti di Xcode (e compilatore associato) hanno utilizzato una costruzione più imbarazzante per aggiornare il riferimento booleano per fermare l'enumerazione.