I've been working on an iOS IOT client app which uses MQTT. After some reading I decided to go with CocoaMQTT.
I have only been programming in swift/iOS for about 2 weeks now, so I thought I should have my base code reviewed here before continuing any further.
The idea is to have most of the MQTT connection handling code in a MQTTViewController
class, which itself subclasses UIViewController
.
This MQTTViewController
class would conform to the CocoaMQTTDelegate
protocol, providing overridable stubs for all delegate functions.
All other view controllers will subclass the MQTTViewController
.
I also want to pass my CocoaMQTT
instance and some state variables back-and-forth, so I don't need to connect each time. Currently, I'm doing this by providing a helper function pushMQTTViewControllerWithIdentifier()
for push and using MQTTPassBackDelegate
protocol function passBackMQTTData()
for pop.
Here's my code:
import UIKit
import CocoaMQTT
class MQTTViewController: UIViewController, CocoaMQTTDelegate, MQTTPassBackDelegate {
// MARK: Internal classes
class MQTTState {
var connected = false
var loggedIn = false
}
// MARK: Properties
var mqtt: CocoaMQTT? {
didSet {
if mqtt == nil {
state.connected = false
state.loggedIn = false
if oldValue?.connState == .CONNECTED {
oldValue?.disconnect()
}
}
}
}
var state = MQTTState()
var username: String?
var password: String?
weak var delegate: MQTTPassBackDelegate? = nil
// MARK: Lifecycle
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
guard mqtt != nil else {
mqttInit()
return
}
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
if self.isMovingFromParentViewController() == true {
delegate?.passBackMQTTData(mqtt, state: state, username: username, password: password)
}
}
// MARK: CocoaMQTTDelegate functions
func mqtt(mqtt: CocoaMQTT, didConnect host: String, port: Int) {
dprint("didConnect \(host):\(port)")
}
func mqtt(mqtt: CocoaMQTT, didConnectAck ack: CocoaMQTTConnAck) {
dprint("didConnectAck \(ack.rawValue)")
}
func mqtt(mqtt: CocoaMQTT, didPublishMessage message: CocoaMQTTMessage, id: UInt16) {
dprint("didPublishMessage with message: \(message.string)")
}
func mqtt(mqtt: CocoaMQTT, didPublishAck id: UInt16) {
dprint("didPublishAck with id: \(id)")
}
func mqtt(mqtt: CocoaMQTT, didReceiveMessage message: CocoaMQTTMessage, id: UInt16 ) {
guard message.string != nil else {
dprint("didReceivedMessage: NOT STRING with id \(id)")
return
}
dprint("didReceivedMessage: \(message.string) with id \(id)")
}
func mqtt(mqtt: CocoaMQTT, didSubscribeTopic topic: String) {
dprint("didSubscribeTopic to \(topic)")
}
func mqtt(mqtt: CocoaMQTT, didUnsubscribeTopic topic: String) {
dprint("didUnsubscribeTopic to \(topic)")
}
func mqttDidPing(mqtt: CocoaMQTT) {
dprint("didPing")
}
func mqttDidReceivePong(mqtt: CocoaMQTT) {
dprint("didReceivePong")
}
func mqttDidDisconnect(mqtt: CocoaMQTT, withError err: NSError?) {
dprint("mqttDidDisconnect")
}
// MARK: MQTTPassBackDelegate functions
func passBackMQTTData(mqtt: CocoaMQTT?, state: AnyObject, username: String?, password: String?) {
dprint("passBackMQTTData")
self.mqtt = mqtt
self.state = state as! MQTTState
self.username = username
self.password = password
}
// MARK: Helpers
final func pushMQTTViewControllerWithIdentifier(identifier: String) {
let vc = storyboard?.instantiateViewControllerWithIdentifier(identifier) as! MQTTViewController
vc.mqtt = mqtt
vc.state = state
vc.username = username
vc.password = password
vc.delegate = self
navigationController!.pushViewController(vc, animated: true)
}
final func mqttInit(clientIdPid: String = "ACC_MQTT-" + String(NSProcessInfo().processIdentifier)) {
guard mqtt == nil else {
return // Prevent reinit
}
mqtt = CocoaMQTT(clientId: clientIdPid, host: ACC_MQTT_SERVER, port: UInt16(ACC_MQTT_PORT))
}
final func mqttSetup(username: String, password: String) {
print("Attempting to connect using \(username):\(password)")
if let mqtt = mqtt {
mqtt.username = username
mqtt.password = password
mqtt.cleanSess = false
mqtt.keepAlive = 90
mqtt.delegate = self
}
}
}
protocol MQTTPassBackDelegate: class {
func passBackMQTTData(mqtt: CocoaMQTT?, state: AnyObject, username: String?, password: String?)
}
- Is this the right way going forward?
- Will passing data between view controllers this way result in strong reference cycles?