How to deal with callbacks in ReactiveCocoa 5.0?

414 Views Asked by At

I have an utility class to handle the socket, and in the socket delegate methods i could know the current state of the socket, e.g. didConnected, didReadData and so on. I do not want to write an extra protocol with a delegate to send the socket state indeed.

Actually, there are 2 properties in my utility class, an enum to differentiate the current state of the socket between: didConnected, didReadData, didDisconnected, the other is a Data type value to store the received data from socket. It likes that:

public enum SocketState {
    case unknown, didConnected, didReconnectedFailed, didSentHeartbeatPack, 
         didSentMessage, didReadData, didDisconnected
}
private var currentState: SocketState = .unknown
private var msgData = Data()

After become the delegate of the socket, I have implemented the several methods,

func socket(_ sock: GCDAsyncSocket, didConnectToHost host: String, port: UInt16) {}
func socket(_ sock: GCDAsyncSocket, didWriteDataWithTag tag: Int) {}
func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {}

What I intend to do is while I change the value of the currentState, or I did set the received data to the msgData, in my controller I could capture the 2 values changed simultaneously.

How to make it by use ReactiveCocoa 5.0?

2

There are 2 best solutions below

0
Shaw On BEST ANSWER

I have achieved my goal by use the function "combineLatest" provided by ReactiveSwift.

First of all, announce two MutableProperty's variable, and one SignalProducer, likes below:

private var rac_state = MutableProperty<SocketState>(.unknown)
private var rac_msg = MutableProperty<Data>(Data())
public var rac_SocketStateChanged: SignalProducer<(SocketState, Data), NoError> {
    return SignalProducer.combineLatest(rac_state.producer, rac_msg.producer)
}

Then, change the rac_state.value or rac_mas.value in the socket delegate methods, likes that:

func socketDidDisconnect(_ sock: GCDAsyncSocket, withError err: Error?) {
    rac_state.value = .didDisconnected
}

Finally, make an observer in controller to listen the combined SignalProducer, here is the code:

func configTCPListen() {
    tcpManager.rac_SocketStateChanged
        .startWithValues { [weak self = self] (tuple) in
            switch tuple.0 {
            case .didDisconnected:
                print("TCP has disConnected!")
            default: break
            }
    }
}
2
Qinghua On

Maybe the MutableProperty provided by ReactiveSwift could satisfies you. Your intension is very like what KVO mechanism can do in Objective-C, while Swift does not have. However, MutableProperty class implements the same functionality of which changes could be observed by someone.
Hope those below demos can make you understood the simplest way to use MutableProperty and its usage.

// definition
let currentState: MutableProperty<SocketState> = MutableProperty(.unknown)
let msgData: MutableProperty<Data> = MutableProperty(Data())

// observe changes
currentState.producer.startWithValues { state in
    // process(state)
}
msgData.producer.startWithValues { data in
    // doSomething(withData data)
}

If removed redundant explicit type inference, the above codes would be clean and simple.

// definition
let currentState = MutableProperty(.unknown)
let msgData = MutableProperty(Data())

// observe changes
currentState.producer.startWithValues {
    // process($0)
}
msgData.producer.startWithValues {
    // doSomething(withData $0)
}