在 Swift 3 中将数据写入 NSOutputStream

Writing Data to an NSOutputStream in Swift 3

this question 的解决方案不再适用于 Swift 3.

不再有 Data 的 属性 bytes(以前是 NSData

let data = dataToWrite.first!
self.outputStream.write(&data, maxLength: data.count)

使用这段代码,我得到错误:

Cannot convert value of type 'Data' to expected argument type 'UInt8'

如何将 Data 写入 Swift 3 中的 NSOutputStream

DataNSData是两个独立的类在Swift3,而Data没有bytes属性.

解决方案是将 data 定义为 NSData

类型
let data: NSData = dataToWrite.first!
self.outputStream.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)

根据Migrating to Swift 2.3 or Swift 3 from Swift 2.2:

The migrator will convert most uses of NSData to the new value type Data. However, there are certain methods on NSData that operate on UnsafeMutablePointer, while the corresponding methods on Data use UnsafeMutablePointer. (For example, NSData.getBytes(:length:) is more accepting than Data.copyBytes(:length:).) As a reminder, the in-memory layout of Swift types is not guaranteed.

NSData 有一个 bytes 属性 来访问字节。 Swift 3 中的新 Data 值类型有一个 withUnsafeBytes() 方法,它调用一个带有指向字节的指针的闭包。

这就是将 Data 写入 NSOutputStream 的方式 (不转换为 NSData):

let data = ... // a Data value
let bytesWritten = data.withUnsafeBytes { outputStream.write([=10=], 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 都是由 编译器(如 UInt8Int),进行额外的 UnsafePointer() 不需要转换。

outputStream.write() returns实际写入的字节数。 一般来说,您应该检查那个值。它可以是 -1 如果 写操作失败,或者写的时候小于data.count 到套接字、管道或其他具有流量控制的对象。

Martin 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(
                        [=10=].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
    }
}

只需使用此扩展程序:

Swift 5

extension OutputStream {
  func write(data: Data) -> Int {
    return data.withUnsafeBytes {
      write([=10=].bindMemory(to: UInt8.self).baseAddress!, maxLength: data.count)
    }
  }
}

对于 InputStream

extension InputStream {
  func read(data: inout Data) -> Int {
    return data.withUnsafeMutableBytes {
      read([=11=].bindMemory(to: UInt8.self).baseAddress!, maxLength: data.count)
    }
  }
}

Swift 4

extension OutputStream {
  func write(data: Data) -> Int {
    return data.withUnsafeBytes { write([=12=], maxLength: data.count) }
  }
}
extension InputStream {
  func read(data: inout Data) -> Int {
    return data.withUnsafeMutableBytes { read([=12=], maxLength: data.count) }
  }
}