Запись данных в NSOutputStream в Swift 3
Решение этого вопроса больше не работает с Swift 3.
Больше нет свойства bytes
of Data
(ранее NSData
.
let data = dataToWrite.first!
self.outputStream.write(&data, maxLength: data.count)
С помощью этого кода я получаю сообщение об ошибке:
Cannot convert value of type 'Data' to expected argument type 'UInt8'
Как вы можете написать Data
в NSOutputStream
в Swift 3?
Ответы
Ответ 1
NSData
имел свойство bytes
для доступа к байтам.
Новый тип значения Data
в Swift 3 имеет значение 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
при записи
к разъемам, трубам или другим объектам с контролем потока.
Ответ 2
Мартин Р, спасибо за ваш ответ. Это стало основой для полного решения. Вот он:
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
}
}
Ответ 3
Просто используйте это расширение:
Swift 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)
}
}
}
Swift 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) }
}
}
Ответ 4
Data
и NSData
- два отдельных класса в Swift 3, а Data
не имеет свойства bytes
.
Решение состоит в определении Data
как типа NSData
let data: NSData = dataToWrite.first!
self.outputStream.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)
Согласно Переход на Swift 2.3 или Swift 3 из Swift 2.2:
Мигратор преобразует большинство применений NSData в новый тип данных Data. Тем не менее, существуют определенные методы NSData, которые работают с UnsafeMutablePointer, тогда как соответствующие методы в Data используют UnsafeMutablePointer. (Например, NSData.getBytes(: length:) принимает больше, чем Data.copyBytes(: length:).) Напоминаем, что макет в стиле Swift в памяти не гарантируется.