Reputation: 463
How do I make a custom completion handler for the below function? This is writing to a websocket via Starscream and I want to receive a response if it isn't nil.
open func write(string: String, completion: (() -> ())? = nil) {
guard isConnected else { return }
dequeueWrite(string.data(using: String.Encoding.utf8)!, code: .textFrame, writeCompletion: completion)
}
and here is deqeueWrite func:
private func dequeueWrite(_ data: Data, code: OpCode, writeCompletion: (() -> ())? = nil) {
let operation = BlockOperation()
operation.addExecutionBlock { [weak self, weak operation] in
//stream isn't ready, let's wait
guard let s = self else { return }
guard let sOperation = operation else { return }
var offset = 2
var firstByte:UInt8 = s.FinMask | code.rawValue
var data = data
if [.textFrame, .binaryFrame].contains(code), let compressor = s.compressionState.compressor {
do {
data = try compressor.compress(data)
if s.compressionState.clientNoContextTakeover {
try compressor.reset()
}
firstByte |= s.RSV1Mask
} catch {
// TODO: report error? We can just send the uncompressed frame.
}
}
let dataLength = data.count
let frame = NSMutableData(capacity: dataLength + s.MaxFrameSize)
let buffer = UnsafeMutableRawPointer(frame!.mutableBytes).assumingMemoryBound(to: UInt8.self)
buffer[0] = firstByte
if dataLength < 126 {
buffer[1] = CUnsignedChar(dataLength)
} else if dataLength <= Int(UInt16.max) {
buffer[1] = 126
WebSocket.writeUint16(buffer, offset: offset, value: UInt16(dataLength))
offset += MemoryLayout<UInt16>.size
} else {
buffer[1] = 127
WebSocket.writeUint64(buffer, offset: offset, value: UInt64(dataLength))
offset += MemoryLayout<UInt64>.size
}
buffer[1] |= s.MaskMask
let maskKey = UnsafeMutablePointer<UInt8>(buffer + offset)
_ = SecRandomCopyBytes(kSecRandomDefault, Int(MemoryLayout<UInt32>.size), maskKey)
offset += MemoryLayout<UInt32>.size
for i in 0..<dataLength {
buffer[offset] = data[i] ^ maskKey[i % MemoryLayout<UInt32>.size]
offset += 1
}
var total = 0
while !sOperation.isCancelled {
let stream = s.stream
let writeBuffer = UnsafeRawPointer(frame!.bytes+total).assumingMemoryBound(to: UInt8.self)
let len = stream.write(data: Data(bytes: writeBuffer, count: offset-total))
if len <= 0 {
var error: Error?
let errCode = InternalErrorCode.outputStreamWriteError.rawValue
error = s.errorWithDetail("output stream error during write", code: errCode)
s.doDisconnect(error)
break
} else {
total += len
}
if total >= offset {
if let queue = self?.callbackQueue, let callback = writeCompletion {
queue.async {
callback()
}
}
break
}
}
}
writeQueue.addOperation(operation)
}
So right now I can call this function like this:
socket.write(string: frameJSONSring) { () -> Void in
}
But I'd like a response in that handler so that I can read the response data (if there is any) from the socket. Apparently I can pass a custom response handler as a parameter when calling:
socket.write(string: frameJSONSring) { (CUSTOM_HANDLER_HERE) -> Void in
}
Upvotes: 0
Views: 434
Reputation: 36427
open func write(string: String, completion: ((Int) -> ())?) {
guard isConnected else { return }
let someParameter = 5
dequeueWrite(string.data(using: String.Encoding.utf8)!, code: .textFrame, writeCompletion: completion(someParameter))
}
Notice I:
Int
as a parameter you pass to the handler.completion
to completion(someParameter)
You can then use it like such:
socket.write(string: frameJSONSring) { number in
print(number)
}
You can replace the Int
with any other type you like.
Also no need to do = nil
. When something is an optional then it's already defaulted to nil
.
Upvotes: 1