Swift에서 쓰기 함수를 사용하여 NSOutputStream에 NSData 바이트를 쓰는 중 오류("'()'는 'UInt8'"과 동일하지 않습니다)
문제
저는 Swift를 기반으로 비동기 파일 다운로드를 구축하려고 합니다. 에리카 사둔의 방법.하지만 더 큰 파일을 처리하려면 그것이 필요해서 찾았습니다. NSData 대신 NSOutputStream 사용에 대한 답변, 말이된다.
그러나 나는 그것을 작동시킬 수 없습니다.NSOutputStream 쓰기 함수에 NSData 바이트(NSURLConnection didReceiveData 함수에 있음)를 추가하려고 하면 이 오류가 발생합니다. '()' 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
'에스enumerateByteRangesUsingBlock:
메서드를 사용하는 대신 데이터를 반복하는 방법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 베타 4 이상이 필요합니다.이전 버전의 Xcode(및 관련 컴파일러)는 열거를 중지하기 위해 부울 참조를 업데이트하는 데 더 어색한 구성을 사용했습니다.