web-dev-qa-db-fra.com

Écrire des données sur un NSOutputStream dans Swift 3

La solution de cette question ne fonctionne plus avec Swift 3. 

Il n'y a plus de propriété bytes de Data (anciennement NSData

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

Avec ce code, j'obtiens l'erreur:

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

Comment pouvez-vous écrire Data dans NSOutputStream dans Swift 3?

8
ahyattdev

NSData avait une propriété bytes pour accéder aux octets. Le nouveau type de valeur Data dans Swift 3 utilise à la place une méthode withUnsafeBytes() , qui appelle une fermeture avec un pointeur sur les octets.

Voici comment vous écrivez Data en NSOutputStream (Sans transtypage en NSData):

let data = ... // a Data value
let bytesWritten = data.withUnsafeBytes { outputStream.write($0, maxLength: data.count) }

Remarques: withUnsafeBytes() est une méthode générique:

/// 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

Dans l'appel ci-dessus, ContentType et ResultType sont automatiquement déduits par Le compilateur (en tant que UInt8 et Int), ce qui rend inutiles les conversions supplémentaires de UnsafePointer().

outputStream.write() renvoie le nombre d'octets réellement écrits. En règle générale, vous devriez vérifier cette valeur. Ce peut être -1 si L’opération d’écriture a échoué, ou inférieur à data.count lorsqu’il écrit Sur des sockets, des pipes ou d’autres objets dotés d’un contrôle de flux.

10
Martin R

Martin R , merci pour votre réponse. C'était la base d'une solution complète. C'est ici:

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
Sergey Markelov

Il suffit d'utiliser cette extension (Swift 4)

extension OutputStream {
  func write(data: Data) -> Int {
    return data.withUnsafeBytes { write($0, maxLength: data.count) }
  }
}

Et pour InputStream

extension InputStream {
  func read(data: inout Data) -> Int {
    return data.withUnsafeMutableBytes { read($0, maxLength: data.count) }
  }
}
3
Dmitry Kozlov

Data et NSData sont deux classes distinctes dans Swift 3, et Data ne possède pas la propriété bytes

La solution consiste à définir data comme étant de type NSData

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

SelonMigration vers Swift 2.3 ou Swift 3 à partir de Swift 2.2:

Le migrateur convertira la plupart des utilisations de NSData vers le nouveau type de valeur Data. Cependant, il existe certaines méthodes sur NSData qui fonctionnent sur UnsafeMutablePointer, tandis que les méthodes correspondantes sur Data utilisent UnsafeMutablePointer. (Par exemple, NSData.getBytes (: length :) est plus acceptable que Data.copyBytes (: length :).) Pour rappel, la disposition en mémoire des types Swift n'est pas garantie. 

0
ahyattdev