swift create byte buffer holder for NSStream
You can use a use an Array<UInt8>
as the buffer and pass it as it is documented in Using Swift with Cocoa and Objective-C:
let bufferSize = 1024
var buffer = Array<UInt8>(count: bufferSize, repeatedValue: 0)
let bytesRead = inputStream.read(&buffer, maxLength: bufferSize)
if bytesRead >= 0 {
var output = NSString(bytes: &buffer, length: bytesRead, encoding: NSUTF8StringEncoding)
} else {
// Handle error
}
-[NSInputStream read:maxLength:]
returns a number indicating how many bytes it read (if it's >= 0) or if there was an error (if it's negative). You should check the return value accordingly.
Stream to Get Data - NSInputStream
There are two ways to get data from a stream: polling and using stream events.
Polling is simpler, but will block the thread it is running in. If you use this method, you don't need to perform the setDelegate:
or scheduleInRunLoop:forMode:
calls. Polling is performed by repeatedly calling read:maxLength:
.
NSInteger result;
uint8_t buffer[BUFFER_LEN]; // BUFFER_LEN can be any positive integer
while((result = [iStream read:buffer maxLength:BUFFER_LEN]) != 0) {
if(result > 0) {
// buffer contains result bytes of data to be handled
} else {
// The stream had an error. You can get an NSError object using [iStream streamError]
}
}
// Either the stream ran out of data or there was an error
Using stream events requires setting the delegate and adding the stream to a run loop. Instead of blocking the thread, the stream will send a stream:handleEvent:
message to its delegate when certain events occur, including when it receives data. The delegate can then retrieve the data from the stream. Here is an example stream:handleEvent:
method:
- (void)stream:(NSInputStream *)iStream handleEvent:(NSStreamEvent)event {
BOOL shouldClose = NO;
switch(event) {
case NSStreamEventEndEncountered:
shouldClose = YES;
// If all data hasn't been read, fall through to the "has bytes" event
if(![iStream hasBytesAvailable]) break;
case NSStreamEventHasBytesAvailable: ; // We need a semicolon here before we can declare local variables
uint8_t *buffer;
NSUInteger length;
BOOL freeBuffer = NO;
// The stream has data. Try to get its internal buffer instead of creating one
if(![iStream getBuffer:&buffer length:&length]) {
// The stream couldn't provide its internal buffer. We have to make one ourselves
buffer = malloc(BUFFER_LEN * sizeof(uint8_t));
freeBuffer = YES;
NSInteger result = [iStream read:buffer maxLength:BUFFER_LEN];
if(result < 0) {
// error copying to buffer
break;
}
length = result;
}
// length bytes of data in buffer
if(freeBuffer) free(buffer);
break;
case NSStreamEventErrorOccurred:
// some other error
shouldClose = YES;
break;
}
if(shouldClose) [iStream close];
}
Why is the HTTPBody of a request inside an NSURLProtocol Subclass always nil?
Here's a sample code for reading the httpBody:
Swift 5
extension URLRequest {
func bodySteamAsJSON() -> Any? {
guard let bodyStream = self.httpBodyStream else { return nil }
bodyStream.open()
// Will read 16 chars per iteration. Can use bigger buffer if needed
let bufferSize: Int = 16
let buffer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
var dat = Data()
while bodyStream.hasBytesAvailable {
let readDat = bodyStream.read(buffer, maxLength: bufferSize)
dat.append(buffer, count: readDat)
}
buffer.deallocate()
bodyStream.close()
do {
return try JSONSerialization.jsonObject(with: dat, options: JSONSerialization.ReadingOptions.allowFragments)
} catch {
print(error.localizedDescription)
return nil
}
}
}
Then, in URLProtocol:
override func startLoading() {
...
if let jsonBody = self.request.bodySteamAsJSON() {
print("JSON \(jsonBody)")
}
...
}
Playing Audio on iOS from Socket connection
I solved this in the end, see my answer here
I intended putting the code here, but it would be a lot of copy pasting
iOS send data using socket connection
After doing hard research i found adding \n
at the end of string message indicates my buffer has received whole string.
now start sending a file, so it worked...
To send a String over Sockets, you must mark the end of the string. ie; Add a \n
Related Topics
How Do We Implement Wait/Notify in Swift
How to I Access Argv and Argc in Swift
Uicollectionview Autosize and Dynamic Number of Rows
Swift: Move Uiimage Partly Along Path
Swift Protocol Defining Class Method Returning Self
How to Send Data from iPhone to Watchkit in Os2 in Swift
Swift - How to Get Text Formatting in a Text Editor Like in the Notes App? Swiftui
Nsurlsessiondatadelegate Method Didreceivedata and Others Are Not Called
Passing and Storing Closures/Callbacks in Swift
Swift Combine: Using Timer Publisher in an Observable Object
Realmswift + Multiple Predicate
Convert to Latest Swift Syntax' Breaks the Build Even When There Are No Changes
How to Integrate Uisearchcontroller with Swiftui
How to Set Interactive Push Notifications on iOS8
Swiftui MACos Commands (Menu Bar) and View
How to Retrieve All Contacts Using Cncontact.Predicateforcontacts