web-dev-qa-db-ja.com

Swift 3でNSOutputStreamにデータを書き込む

この質問 の解決策は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)でDataNSOutputStreamに書き込むにはどうすればよいですか?

10
ahyattdev

NSDataには、バイトにアクセスするためのbytesプロパティがありました。 Swift 3の新しいData値型には、代わりにwithUnsafeBytes()メソッドがあり、バイトへのポインターを使用してクロージャを呼び出します。

したがって、これはDataNSOutputStreamに書き込む方法です(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
_

上記の呼び出しでは、ContentTypeResultTypeの両方がコンパイラーによって自動的に推測され(_UInt8_およびIntとして)、追加のUnsafePointer()が作成されます。変換は不要です。

outputStream.write()は、実際に書き込まれたバイト数を返します。一般的には、チェックその値にする必要があります。書き込み操作が失敗した場合は_-1_になる可能性があり、フロー制御を使用してソケット、パイプ、またはその他のオブジェクトに書き込む場合は_data.count_未満になる可能性があります。

14
Martin R

この拡張機能を使用するだけです:

スウィフト5

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)
    }
  }
}

スウィフト4

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) }
  }
}
6
Dmitry Kozlov

マーティン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
    }
}
6
Sergey Markelov

DataNSDataは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タイプのメモリレイアウトは保証されません。

0
ahyattdev