【问题标题】:Writing Data to an NSOutputStream in Swift 3在 Swift 3 中将数据写入 NSOutputStream
【发布时间】:2016-10-31 14:44:00
【问题描述】:

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

不再有 bytesData 属性(以前的 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

【问题讨论】:

    标签: swift nsdata foundation swift3 nsoutputstream


    【解决方案1】:

    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
    

    在上述调用中, ContentTypeResultType 都会自动推断为 编译器(如UInt8Int),使附加 UnsafePointer() 不需要转换。

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

    【讨论】:

      【解决方案2】:

      只需使用这个扩展:

      斯威夫特 5

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

      对于输入流

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

      【讨论】:

      • 我遇到了一些类似的问题,并尝试使用前面提到的“extension OutputStream”和代码“let bytesWritten = data.withUnsafeBytes { outputStream.write....”。在这两种情况下,我都会写入 -1 个字节。我一定是做错了什么。
      • @Michel 您的连接似乎有问题
      • 编译在输入流扩展上显示此错误“重叠访问‘数据’,但修改需要独占访问;考虑复制到局部变量”
      • @MarkBridges 在返回闭包之外获取计数。这样就编译器而言没有竞争条件```让count = data.count返回数据......```
      【解决方案3】:

      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(
                              $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
          }
      }
      

      【讨论】:

        【解决方案4】:

        DataNSData 在 Swift 3 中是两个独立的类,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

        迁移器会将 NSData 的大多数用途转换为新的值类型 Data。但是,NSData 上有某些方法对 UnsafeMutablePointer 进行操作,而 Data 上的相应方法使用 UnsafeMutablePointer。 (例如,NSData.getBytes(:length:) 比 Data.copyBytes(:length:) 更容易接受。)提醒一下,Swift 类型的内存布局并不能保证。

        【讨论】:

          猜你喜欢
          • 2023-03-15
          • 2012-07-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多