この質問 の解決策はSwift 3では機能しなくなりました。
bytes
(以前のData
)のプロパティNSData
はなくなりました。
let data = dataToWrite.first!
self.outputStream.write(&data, maxLength: data.count)
このコードでは、次のエラーが発生します。
Cannot convert value of type 'Data' to expected argument type 'UInt8'
Swift 3)でData
をNSOutputStream
に書き込むにはどうすればよいですか?
NSData
には、バイトにアクセスするためのbytes
プロパティがありました。 Swift 3の新しいData
値型には、代わりにwithUnsafeBytes()
メソッドがあり、バイトへのポインターを使用してクロージャを呼び出します。
したがって、これはData
をNSOutputStream
に書き込む方法です(NSData
にキャストせずに):
_let data = ... // a Data value
let bytesWritten = data.withUnsafeBytes { outputStream.write($0, maxLength: data.count) }
_
備考:withUnsafeBytes()
はジェネリックメソッドです:
_/// Access the bytes in the data.
///
/// - warning: The byte pointer argument should not be stored and used outside of the lifetime of the call to the closure.
public func withUnsafeBytes<ResultType, ContentType>(_ body: @noescape (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType
_
上記の呼び出しでは、ContentType
とResultType
の両方がコンパイラーによって自動的に推測され(_UInt8
_およびInt
として)、追加のUnsafePointer()
が作成されます。変換は不要です。
outputStream.write()
は、実際に書き込まれたバイト数を返します。一般的には、チェックその値にする必要があります。書き込み操作が失敗した場合は_-1
_になる可能性があり、フロー制御を使用してソケット、パイプ、またはその他のオブジェクトに書き込む場合は_data.count
_未満になる可能性があります。
この拡張機能を使用するだけです:
extension OutputStream {
func write(data: Data) -> Int {
return data.withUnsafeBytes {
write($0.bindMemory(to: UInt8.self).baseAddress!, maxLength: data.count)
}
}
}
そしてInputStreamの場合
extension InputStream {
func read(data: inout Data) -> Int {
return data.withUnsafeMutableBytes {
read($0.bindMemory(to: UInt8.self).baseAddress!, maxLength: data.count)
}
}
}
extension OutputStream {
func write(data: Data) -> Int {
return data.withUnsafeBytes { write($0, maxLength: data.count) }
}
}
extension InputStream {
func read(data: inout Data) -> Int {
return data.withUnsafeMutableBytes { read($0, maxLength: data.count) }
}
}
マーティンR、ご回答ありがとうございます。それが完全なソリューションの基盤でした。ここにあります:
extension OutputStream {
/// Write String to outputStream
///
/// - parameter string: The string to write.
/// - parameter encoding: The String.Encoding to use when writing the string. This will default to UTF8.
/// - parameter allowLossyConversion: Whether to permit lossy conversion when writing the string.
///
/// - returns: Return total number of bytes written upon success. Return -1 upon failure.
func write(_ string: String, encoding: String.Encoding = String.Encoding.utf8, allowLossyConversion: Bool = true) -> Int {
if let data = string.data(using: encoding, allowLossyConversion: allowLossyConversion) {
var bytesRemaining = data.count
var totalBytesWritten = 0
while bytesRemaining > 0 {
let bytesWritten = data.withUnsafeBytes {
self.write(
$0.advanced(by: totalBytesWritten),
maxLength: bytesRemaining
)
}
if bytesWritten < 0 {
// "Can not OutputStream.write(): \(self.streamError?.localizedDescription)"
return -1
} else if bytesWritten == 0 {
// "OutputStream.write() returned 0"
return totalBytesWritten
}
bytesRemaining -= bytesWritten
totalBytesWritten += bytesWritten
}
return totalBytesWritten
}
return -1
}
}
Data
とNSData
はSwift 3の2つの別個のクラスであり、Data
にはbytes
プロパティがありません。
解決策は、data
をタイプNSData
として定義することです。
let data: NSData = dataToWrite.first!
self.outputStream.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)
Swift 2.3またはSwift 3 from Swift = 2.2:
移行者は、NSDataのほとんどの使用を新しい値タイプのデータに変換します。ただし、NSDataにはUnsafeMutablePointerで動作する特定のメソッドがあり、Dataの対応するメソッドはUnsafeMutablePointerを使用します。 (たとえば、NSData.getBytes(:length :)はData.copyBytes(:length :)よりも受け入れやすくなっています。) -Swiftタイプのメモリレイアウトは保証されません。