Writing Data to an Outputstream with Swift 5+

Writing Data to an OutputStream with Swift 5+

The trick is to use bindMemory function:

func write(_ data: Data) -> Int {
return data.withUnsafeBytes({ (rawBufferPointer: UnsafeRawBufferPointer) -> Int in
let bufferPointer = rawBufferPointer.bindMemory(to: UInt8.self)
return self.write(bufferPointer.baseAddress!, maxLength: data.count)
})
}

While this works with Swift 5.0, there are apparently some issues; see a related forum discussion.

Writing Data to an NSOutputStream in Swift 3

NSData had a bytes property to access the bytes.
The new Data value type in Swift 3 has a withUnsafeBytes()
method instead, which calls a closure with a pointer to the bytes.

So this is how you write Data to an NSOutputStream
(without casting to NSData):

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

Remarks:
withUnsafeBytes() is a generic method:

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

In the above call,
both ContentType and ResultType are automatically inferred by
the compiler (as UInt8 and Int), making additional
UnsafePointer() conversions unnecessary.

outputStream.write() returns the number of bytes actually written.
Generally, you should check that value. It can be -1 if
the write operation failed, or less than data.count when writing
to sockets, pipes, or other objects with a flow control.

How to check for success when writing with OutputStream?

Assuming you know that the sendMessage(_:) method is getting called and all you're looking to do is check whether or not the write was successful, this can be done in a straight forward way by looking at the return value of the write method (documentation) Here's a quick example.

@IBAction func sendMessage(sender: AnyObject!) {
guard let outputStream = outputStream else {
print("Connection not create yet ! =====> Return")
return
}

guard let text = textfield?.text,
data: NSData = text.data(using: String.Encoding.utf8) else {
print("no data")
return
}

print("\(outputStream) ==> Pass Data : \(text)")
outputStream.open()
defer {
outputStream.close()
}

let result = outputStream.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)
if result == 0 {
print("Stream at capacity")
} else if result == -1 {
print("Operation failed: \(outputStream.streamError)")
} else {
print("The number of bytes written is \(result)")
}
}

Writing a String to an NSOutputStream in Swift

There are two issues here. The first is that you're passing data to outputStream.write() and not data.bytes (like you passed [data bytes] in your Objective-C code). The second issue is that data.bytes returns an UnsafePointer<Void>, but NSOutputStream.write() takes an UnsafePointer<UInt8>. Luckily, UnsafePointer has a way to convert between types:

/// Convert from a UnsafePointer of a different type.
///
/// This is a fundamentally unsafe conversion.
init<U>(_ from: UnsafePointer<U>)

Putting those things together makes your code look something like this:

let data: NSData = mystring.dataUsingEncoding(NSUTF8StringEncoding)!
outputStream.write(UnsafePointer<UInt8>(data.bytes), maxLength: data.length)

How to send NSData over an OutputStream

Pretty sure you want to replace this:

let length = self.inputStream!.read(&buffer, maxLength: buffer.count)
let data = NSData.init(bytes: buffer, length: buffer.count)

With

let length = self.inputStream!.read(&buffer, maxLength: buffer.count)
let data = NSData.init(bytes: buffer, length: length)

Also, I am not 100% sure that the random blocks of data will always be ok to use to make the audio buffers. You might need to collect up the data first into a bigger block of NSData.

Right now, since you always pass in blocks of 8192 (even if you read less), the buffer creation probably always succeeds. It might not now.

Sending bytes on outputstream with Swift

I don't see anything wrong with your code but the conversion to Data is not needed:

bytes.withUnsafeBytes {
guard let pointer = $0.baseAddress?.assumingMemoryBound(to: UInt8.self) else {
return
}
outputStream.write(pointer, maxLength: bytes.count)
}

since [UInt8] conforms to ContiguousBytes.

Actually, the following is also possible:

bytes.withUnsafeBufferPointer {
guard let baseAddress = $0.baseAddress else { return }
outputStream.write(baseAddress, maxLength: bytes.count)
}


Related Topics



Leave a reply



Submit