From 51973d4e53b156e2e251b15be9636077650dc9e7 Mon Sep 17 00:00:00 2001 From: Adolfo Martinelli Date: Thu, 15 Sep 2016 22:59:47 -0700 Subject: [PATCH] Swift 3.0 Support (#8) * Swift 3.0 Migration * Update README documentation * Refactor and update public interfaces * Bump major version and update podspec --- .travis.yml | 4 +- README.md | 48 ++-- SwiftMQTT.podspec | 6 +- SwiftMQTT/SwiftMQTT.xcodeproj/project.pbxproj | 15 +- .../xcshareddata/xcschemes/SwiftMQTT.xcscheme | 2 +- SwiftMQTT/SwiftMQTT/MQTTExtensions.swift | 97 ++++---- SwiftMQTT/SwiftMQTT/MQTTSession.swift | 211 +++++++++--------- .../SwiftMQTT/MQTTSessionStreamDelegate.swift | 79 +++---- .../SwiftMQTT/Models/MQTTConnAckPacket.swift | 14 +- .../SwiftMQTT/Models/MQTTConnectPacket.swift | 62 +++-- .../Models/MQTTDisconnectPacket.swift | 6 +- SwiftMQTT/SwiftMQTT/Models/MQTTPacket.swift | 26 +-- .../Models/MQTTPacketFixedHeader.swift | 10 +- .../SwiftMQTT/Models/MQTTPingPacket.swift | 8 +- SwiftMQTT/SwiftMQTT/Models/MQTTPingResp.swift | 3 +- SwiftMQTT/SwiftMQTT/Models/MQTTPubAck.swift | 22 +- SwiftMQTT/SwiftMQTT/Models/MQTTPubMsg.swift | 15 +- .../SwiftMQTT/Models/MQTTPublishPacket.swift | 52 ++--- .../SwiftMQTT/Models/MQTTSubAckPacket.swift | 7 +- .../SwiftMQTT/Models/MQTTSubPacket.swift | 24 +- .../SwiftMQTT/Models/MQTTUnSubAckPacket.swift | 9 +- .../SwiftMQTT/Models/MQTTUnsubPacket.swift | 22 +- SwiftMQTT/SwiftMQTTTests/SwiftMQTTTests.swift | 76 ++++--- .../project.pbxproj | 68 ++---- .../SwiftMQTTExample/AppDelegate.swift | 12 +- .../Base.lproj/Main.storyboard | 62 ++--- .../SwiftMQTTExample/MQTTViewController.swift | 135 +++++------ 27 files changed, 529 insertions(+), 566 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8065ada..3565cfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: objective-c -osx_image: xcode7.3 +osx_image: xcode8 before_install: - brew update - brew install mosquitto script: - /usr/local/opt/mosquitto/sbin/mosquitto -d -- xcodebuild -project SwiftMQTT/SwiftMQTT.xcodeproj -scheme SwiftMQTT -sdk iphonesimulator test \ No newline at end of file +- xcodebuild -project SwiftMQTT/SwiftMQTT.xcodeproj -scheme SwiftMQTT -sdk iphonesimulator -destination "name=iPhone 6s" test \ No newline at end of file diff --git a/README.md b/README.md index fe14066..bb76ecd 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,27 @@ # SwiftMQTT -MQTT Client in pure swift ❤️ -Master: +MQTT Client in pure Swift ❤️️ + [![Build Status](https://travis-ci.org/aciidb0mb3r/SwiftMQTT.svg)](https://travis-ci.org/aciidb0mb3r/SwiftMQTT) +[![Version](https://img.shields.io/cocoapods/v/SwiftMQTT.svg?style=flat)](http://cocoapods.org/pods/SwiftMQTT) +[![License](https://img.shields.io/cocoapods/l/SwiftMQTT.svg?style=flat)](http://cocoapods.org/pods/SwiftMQTT) -# Info -* Fully written in swift from ground up -* Closures everywhere :D +## Info +* Fully written in Swift from ground up +* Closures everywhere 😃 * Includes test cases and sample project * Based on MQTT Version 3.1.1 (http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718043) ![Sample Project Screenshot](http://i.imgur.com/9lefVmVl.png) -# How to use +## How to use -## Create MQTTSession object: +### Create Session ```swift mqttSession = MQTTSession(host: "localhost", port: 1883, clientID: "swift", cleanSession: true, keepAlive: 15, useSSL: false) ``` -## Connect +### Connect ```swift mqttSession.connect { (succeeded, error) -> Void in if succeeded { @@ -28,49 +30,49 @@ mqttSession.connect { (succeeded, error) -> Void in } ``` -## Subscribe +### Subscribe ```swift -mqttSession.subscribe("/hey/cool", qos: MQTTQoS.AtLeastOnce) { (succeeded, error) -> Void in +mqttSession.subscribe(to: "/hey/cool", delivering: .atLeastOnce) { (succeeded, error) -> Void in if succeeded { print("Subscribed!") } } ``` -## Unsubscribe +### Unsubscribe ```swift - mqttSession.unSubscribe(["/ok/cool", "/no/ok"]) { (succeeded, error) -> Void in + mqttSession.unSubscribe(from: ["/ok/cool", "/no/ok"]) { (succeeded, error) -> Void in if succeeded { print("unSubscribed!") } } ``` -## Publish + +### Publish ```swift let jsonDict = ["hey" : "sup"] -let data = try! NSJSONSerialization.dataWithJSONObject(jsonDict, options: NSJSONWritingOptions.PrettyPrinted) +let data = try! JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted) -mqttSession.publishData(data, onTopic: "/hey/wassap", withQoS: MQTTQoS.AtLeastOnce, shouldRetain: false) { (succeeded, error) -> Void in +mqttSession.publish(data, in: "/hey/wassap", delivering: .atLeastOnce, retain: false) { (succeeded, error) -> Void in if succeeded { print("Published!") } } -``` -## Conform to `MQTTSessionDelegate` to receive messages +``` +### Conform to `MQTTSessionDelegate` to receive messages ```swift mqttSession.delegate = self ``` ```swift -func mqttSession(session: MQTTSession, didReceiveMessage message: NSData, onTopic topic: String) { - let stringData = NSString(data: message, encoding: NSUTF8StringEncoding) as! String - print("data received on topic \(topic) message \(stringData)") +func mqttSession(session: MQTTSession, received message: Data, in topic: String) { + let string = String(data: message, encoding: .utf8)! } ``` -# Installation +## Installation -## CocoaPods +### CocoaPods Install using [CocoaPods](http://cocoapods.org) by adding the following lines to your Podfile: @@ -79,5 +81,5 @@ use_frameworks! pod 'SwiftMQTT' ```` -# License +## License MIT diff --git a/SwiftMQTT.podspec b/SwiftMQTT.podspec index 4478b73..92c68ed 100644 --- a/SwiftMQTT.podspec +++ b/SwiftMQTT.podspec @@ -2,10 +2,10 @@ Pod::Spec.new do |s| s.name = "SwiftMQTT" - s.version = "1.0.2" - s.summary = "MQTT Client in pure swift" + s.version = "2.0.0" + s.summary = "MQTT Client in pure Swift" s.description = <<-DESC - MQTT Client in pure swift + MQTT Client in Swift 3.0 based on MQTT Version 3.1.1 DESC s.homepage = "https://github.com/aciidb0mb3r/SwiftMQTT" diff --git a/SwiftMQTT/SwiftMQTT.xcodeproj/project.pbxproj b/SwiftMQTT/SwiftMQTT.xcodeproj/project.pbxproj index 52e5b2f..90f0601 100644 --- a/SwiftMQTT/SwiftMQTT.xcodeproj/project.pbxproj +++ b/SwiftMQTT/SwiftMQTT.xcodeproj/project.pbxproj @@ -113,6 +113,7 @@ 5471A8971BF228900079610F /* Products */, ); sourceTree = ""; + usesTabs = 0; }; 5471A8971BF228900079610F /* Products */ = { isa = PBXGroup; @@ -202,11 +203,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; - LastUpgradeCheck = 0710; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Ankit; TargetAttributes = { 5471A8951BF228900079610F = { CreatedOnToolsVersion = 7.1; + LastSwiftMigration = 0800; }; 5471A89F1BF228900079610F = { CreatedOnToolsVersion = 7.1; @@ -305,11 +307,12 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = dwarf; @@ -353,11 +356,12 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = 1; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; @@ -374,6 +378,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.1; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -397,6 +402,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -415,6 +421,7 @@ PRODUCT_BUNDLE_IDENTIFIER = im.ankit.SwiftMQTT; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; }; name = Release; }; @@ -425,6 +432,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.ankit.SwiftMQTTTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -435,6 +443,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.ankit.SwiftMQTTTests; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/SwiftMQTT/SwiftMQTT.xcodeproj/xcshareddata/xcschemes/SwiftMQTT.xcscheme b/SwiftMQTT/SwiftMQTT.xcodeproj/xcshareddata/xcschemes/SwiftMQTT.xcscheme index 20573b1..10f0b3b 100644 --- a/SwiftMQTT/SwiftMQTT.xcodeproj/xcshareddata/xcschemes/SwiftMQTT.xcscheme +++ b/SwiftMQTT/SwiftMQTT.xcodeproj/xcshareddata/xcschemes/SwiftMQTT.xcscheme @@ -1,6 +1,6 @@ 0) { - digit |= 0x80; + var digit = UInt8(lengthOfRemainingData % 128) + lengthOfRemainingData /= 128 + if lengthOfRemainingData > 0 { + digit |= 0x80 } - self.appendBytes(&digit, length: 1) - } while (lengthOfRemainingData > 0); + append(&digit, count: 1) + } while lengthOfRemainingData > 0 } - func mqtt_appendUInt8(data: UInt8) { + mutating func mqtt_append(_ data: UInt8) { var varData = data - self.appendBytes(&varData, length: 1) + append(&varData, count: 1) } - ///Appends two bytes - ///Big Endian - func mqtt_appendUInt16(data: UInt16) { + // Appends two bytes + // Big Endian + mutating func mqtt_append(_ data: UInt16) { let byteOne = UInt8(data / 256) let byteTwo = UInt8(data % 256) - self.mqtt_appendUInt8(byteOne) - self.mqtt_appendUInt8(byteTwo) + mqtt_append(byteOne) + mqtt_append(byteTwo) } - func mqtt_appendData(data: NSData) { - self.mqtt_appendUInt16(UInt16(data.length)) - self.appendData(data) + mutating func mqtt_append(_ data: Data) { + mqtt_append(UInt16(data.count)) + append(data) } - func mqtt_appendString(string: String) { - self.mqtt_appendUInt16(UInt16(string.characters.count)) - self.appendData(string.dataUsingEncoding(NSUTF8StringEncoding)!) + mutating func mqtt_append(_ string: String) { + mqtt_append(UInt16(string.characters.count)) + append(string.data(using: .utf8)!) } } diff --git a/SwiftMQTT/SwiftMQTT/MQTTSession.swift b/SwiftMQTT/SwiftMQTT/MQTTSession.swift index 09f64ed..a71e787 100644 --- a/SwiftMQTT/SwiftMQTT/MQTTSession.swift +++ b/SwiftMQTT/SwiftMQTT/MQTTSession.swift @@ -9,28 +9,29 @@ import Foundation public protocol MQTTSessionDelegate { - func mqttSession(session: MQTTSession, didReceiveMessage message: NSData, onTopic topic: String) - func didDisconnectSession(session: MQTTSession) - func socketErrorOccurred(session: MQTTSession) + func mqttDidReceive(message data: Data, in topic: String, from session: MQTTSession) + func mqttDidDisconnect(session: MQTTSession) + func mqttSocketErrorOccurred(session: MQTTSession) } -public typealias MQTTSessionCompletionBlock = (succeeded: Bool, error: ErrorType) -> Void +public typealias MQTTSessionCompletionBlock = (_ succeeded: Bool, _ error: Error) -> Void -public class MQTTSession: MQTTSessionStreamDelegate { - - public let cleanSession: Bool - public let keepAlive: UInt16 - public let clientID: String +open class MQTTSession: MQTTSessionStreamDelegate { + + open let cleanSession: Bool + open let keepAlive: UInt16 + open let clientID: String - public var username: String? - public var password: String? - public var willMessage: MQTTPubMsg? - public var delegate: MQTTSessionDelegate? + open var username: String? + open var password: String? + open var lastWillMessage: MQTTPubMsg? + + open var delegate: MQTTSessionDelegate? - private var keepAliveTimer: NSTimer! - private var connectionCompletionBlock: MQTTSessionCompletionBlock? - private var messagesCompletionBlocks = [UInt16 : MQTTSessionCompletionBlock]() - private var stream: MQTTSessionStream + fileprivate var keepAliveTimer: Timer! + fileprivate var connectionCompletionBlock: MQTTSessionCompletionBlock? + fileprivate var messagesCompletionBlocks = [UInt16: MQTTSessionCompletionBlock]() + fileprivate var stream: MQTTSessionStream public init(host: String, port: UInt16, clientID: String, cleanSession: Bool, keepAlive: UInt16, useSSL: Bool = false) { stream = MQTTSessionStream(host: host, port: port, ssl: useSSL) @@ -39,154 +40,154 @@ public class MQTTSession: MQTTSessionStreamDelegate { self.keepAlive = keepAlive } - public func publishData(data: NSData, onTopic: String, withQoS: MQTTQoS, shouldRetain: Bool, completion: MQTTSessionCompletionBlock?) { - let msgID = self.nextMessageID() - let pubMsg = MQTTPubMsg(topic: onTopic, message: data, retain: shouldRetain, QoS: withQoS) + open func publish(_ data: Data, in topic: String, delivering qos: MQTTQoS, retain: Bool, completion: MQTTSessionCompletionBlock?) { + let msgID = nextMessageID() + let pubMsg = MQTTPubMsg(topic: topic, payload: data, retain: retain, QoS: qos) let publishPacket = MQTTPublishPacket(messageID: msgID, message: pubMsg) - if self.sendPacket(publishPacket) { - self.messagesCompletionBlocks[msgID] = completion - if withQoS == MQTTQoS.AtMostOnce { - completion?(succeeded: true, error: MQTTSessionError.None) + if send(publishPacket) { + messagesCompletionBlocks[msgID] = completion + if qos == .atMostOnce { + completion?(true, MQTTSessionError.none) } } else { - completion?(succeeded: false, error: MQTTSessionError.SocketError) + completion?(false, MQTTSessionError.socketError) } } - public func subscribe(topic: String, qos: MQTTQoS, completion: MQTTSessionCompletionBlock?) { - self.subscribe([topic : qos], completion: completion) + open func subscribe(to topic: String, delivering qos: MQTTQoS, completion: MQTTSessionCompletionBlock?) { + subscribe(to: [topic: qos], completion: completion) } - public func subscribe(topics: [String : MQTTQoS], completion: MQTTSessionCompletionBlock?) { - let msgID = self.nextMessageID() + open func subscribe(to topics: [String: MQTTQoS], completion: MQTTSessionCompletionBlock?) { + let msgID = nextMessageID() let subscribePacket = MQTTSubPacket(topics: topics, messageID: msgID) - if self.sendPacket(subscribePacket) { - self.messagesCompletionBlocks[msgID] = completion + if send(subscribePacket) { + messagesCompletionBlocks[msgID] = completion } else { - completion?(succeeded: false, error: MQTTSessionError.SocketError) + completion?(false, MQTTSessionError.socketError) } - } - public func unSubscribe(topic: String, completion: MQTTSessionCompletionBlock?) { - self.unSubscribe([topic], completion: completion) + open func unSubscribe(from topic: String, completion: MQTTSessionCompletionBlock?) { + unSubscribe(from: [topic], completion: completion) } - public func unSubscribe(topics: [String], completion: MQTTSessionCompletionBlock?) { - let msgID = self.nextMessageID() + open func unSubscribe(from topics: [String], completion: MQTTSessionCompletionBlock?) { + let msgID = nextMessageID() let unSubPacket = MQTTUnsubPacket(topics: topics, messageID: msgID) - if self.sendPacket(unSubPacket) { - self.messagesCompletionBlocks[msgID] = completion + if send(unSubPacket) { + messagesCompletionBlocks[msgID] = completion } else { - completion?(succeeded: false, error: MQTTSessionError.SocketError) + completion?(false, MQTTSessionError.socketError) } } - public func connect(completion: MQTTSessionCompletionBlock?) { - //Open Stream + open func connect(completion: MQTTSessionCompletionBlock?) { + // Open Stream stream.delegate = self stream.createStreamConnection() - keepAliveTimer = NSTimer(timeInterval: Double(self.keepAlive), target: self, selector: #selector(MQTTSession.keepAliveTimerFired), userInfo: nil, repeats: true) - NSRunLoop.mainRunLoop().addTimer(keepAliveTimer, forMode: NSDefaultRunLoopMode) + keepAliveTimer = Timer(timeInterval: Double(keepAlive), target: self, selector: #selector(MQTTSession.keepAliveTimerFired), userInfo: nil, repeats: true) + RunLoop.main.add(keepAliveTimer, forMode: .defaultRunLoopMode) - //Create Connect Packet - let connectPacket = MQTTConnectPacket(clientID: self.clientID, cleanSession: self.cleanSession, keepAlive: self.keepAlive) - //Set Optional vars - connectPacket.username = self.username - connectPacket.password = self.password - connectPacket.willMessage = self.willMessage + // Create Connect Packet + let connectPacket = MQTTConnectPacket(clientID: clientID, cleanSession: cleanSession, keepAlive: keepAlive) + // Set Optional vars + connectPacket.username = username + connectPacket.password = password + connectPacket.lastWillMessage = lastWillMessage - if self.sendPacket(connectPacket) { - self.connectionCompletionBlock = completion + if send(connectPacket) { + connectionCompletionBlock = completion } else { - completion?(succeeded: false, error: MQTTSessionError.SocketError) + completion?(false, MQTTSessionError.socketError) } } - public func disconnect() { + open func disconnect() { let disconnectPacket = MQTTDisconnectPacket() - self.sendPacket(disconnectPacket) - self.disconnectionCleanup() + send(disconnectPacket) + cleanupDisconnection() } - private func disconnectionCleanup() { + fileprivate func cleanupDisconnection() { stream.closeStreams() keepAliveTimer?.invalidate() - self.delegate?.didDisconnectSession(self) + delegate?.mqttDidDisconnect(session: self) } - private func sendPacket(packet: MQTTPacket) -> Bool { - let writtenLength = stream.sendPacket(packet) + @discardableResult + fileprivate func send(_ packet: MQTTPacket) -> Bool { + let writtenLength = stream.send(packet) let didWriteSuccessfully = writtenLength != -1 if !didWriteSuccessfully { - self.delegate?.socketErrorOccurred(self) - self.disconnectionCleanup() + delegate?.mqttSocketErrorOccurred(session: self) + cleanupDisconnection() } return didWriteSuccessfully } - private func parseReceivedData(data: NSData, mqttHeader: MQTTPacketFixedHeader) { - if mqttHeader.packetType == .Connack { - let connackPacket = MQTTConnAckPacket(header: mqttHeader, networkData: data) - let success = (connackPacket.response == .ConnectionAccepted) - self.connectionCompletionBlock?(succeeded: success, error: connackPacket.response) - self.connectionCompletionBlock = nil - } - if mqttHeader.packetType == .SubAck { - let subAckPacket = MQTTSubAckPacket(header: mqttHeader, networkData: data) - self.callSuccessCompletionBlockForMessageID(subAckPacket.messageID) - } - if mqttHeader.packetType == .UnSubAck { - let unSubAckPacket = MQTTUnSubAckPacket(header: mqttHeader, networkData: data) - self.callSuccessCompletionBlockForMessageID(unSubAckPacket.messageID) - } - if mqttHeader.packetType == .PubAck { - let pubAck = MQTTPubAck(header: mqttHeader, networkData: data) - self.callSuccessCompletionBlockForMessageID(pubAck.messageID) - } - if mqttHeader.packetType == .Publish { - let publishPacket = MQTTPublishPacket(header: mqttHeader, networkData: data) - self.sendPubAckForMessageID(publishPacket.messageID) - self.delegate?.mqttSession(self, didReceiveMessage: publishPacket.message.message, onTopic: publishPacket.message.topic) - } - if mqttHeader.packetType == .PingResp { - _ = MQTTPingResp(header: mqttHeader) + fileprivate func parse(_ networkData: Data, header: MQTTPacketFixedHeader) { + switch header.packetType { + case .connAck: + let connAckPacket = MQTTConnAckPacket(header: header, networkData: networkData) + let success = (connAckPacket.response == .connectionAccepted) + connectionCompletionBlock?(success, connAckPacket.response) + connectionCompletionBlock = nil + case .subAck: + let subAckPacket = MQTTSubAckPacket(header: header, networkData: networkData) + callSuccessCompletionBlock(for: subAckPacket.messageID) + case .unSubAck: + let unSubAckPacket = MQTTUnSubAckPacket(header: header, networkData: networkData) + callSuccessCompletionBlock(for: unSubAckPacket.messageID) + case .pubAck: + let pubAck = MQTTPubAck(header: header, networkData: networkData) + callSuccessCompletionBlock(for: pubAck.messageID) + case .publish: + let publishPacket = MQTTPublishPacket(header: header, networkData: networkData) + sendPubAck(for: publishPacket.messageID) + let payload = publishPacket.message.payload + let topic = publishPacket.message.topic + delegate?.mqttDidReceive(message: payload, in: topic, from: self) + case .pingResp: + _ = MQTTPingResp(header: header) + default: + return } } - private func sendPubAckForMessageID(mid: UInt16) { - let pubAck = MQTTPubAck(messageID: mid) - self.sendPacket(pubAck) + fileprivate func sendPubAck(for messageId: UInt16) { + let pubAck = MQTTPubAck(messageID: messageId) + send(pubAck) } - private func callSuccessCompletionBlockForMessageID(mid: UInt16) { - let completionBlock = self.messagesCompletionBlocks[mid] - self.messagesCompletionBlocks[mid] = nil - completionBlock?(succeeded: true, error: MQTTSessionError.None) + fileprivate func callSuccessCompletionBlock(for messageId: UInt16) { + let completionBlock = messagesCompletionBlocks[messageId] + messagesCompletionBlocks[messageId] = nil + completionBlock?(true, MQTTSessionError.none) } - @objc private func keepAliveTimerFired() { + @objc fileprivate func keepAliveTimerFired() { let mqttPingReq = MQTTPingPacket() - self.sendPacket(mqttPingReq) + send(mqttPingReq) } - private func nextMessageID() -> UInt16 { + fileprivate func nextMessageID() -> UInt16 { struct MessageIDHolder { static var messageID = UInt16(0) } MessageIDHolder.messageID += 1 return MessageIDHolder.messageID } - - //MARK:- MQTTSessionStreamDelegates - func streamErrorOccurred(stream: MQTTSessionStream) { - self.delegate?.socketErrorOccurred(self) + // MARK: - MQTTSessionStreamDelegate + + func mqttReceived(_ data: Data, header: MQTTPacketFixedHeader, in stream: MQTTSessionStream) { + parse(data, header: header) } - func receivedData(stream: MQTTSessionStream, data: NSData, withMQTTHeader header: MQTTPacketFixedHeader) { - self.parseReceivedData(data, mqttHeader: header) + func mqttErrorOccurred(in stream: MQTTSessionStream) { + delegate?.mqttSocketErrorOccurred(session: self) } - + } diff --git a/SwiftMQTT/SwiftMQTT/MQTTSessionStreamDelegate.swift b/SwiftMQTT/SwiftMQTT/MQTTSessionStreamDelegate.swift index 3dd77b9..7baee1f 100644 --- a/SwiftMQTT/SwiftMQTT/MQTTSessionStreamDelegate.swift +++ b/SwiftMQTT/SwiftMQTT/MQTTSessionStreamDelegate.swift @@ -9,18 +9,18 @@ import Foundation protocol MQTTSessionStreamDelegate { - func streamErrorOccurred(stream: MQTTSessionStream) - func receivedData(stream: MQTTSessionStream, data: NSData, withMQTTHeader header: MQTTPacketFixedHeader) + func mqttErrorOccurred(in stream: MQTTSessionStream) + func mqttReceived(_ data: Data, header: MQTTPacketFixedHeader, in stream: MQTTSessionStream) } -class MQTTSessionStream: NSObject, NSStreamDelegate { - +class MQTTSessionStream: NSObject, StreamDelegate { + internal let host: String internal let port: UInt16 internal let ssl: Bool - private var inputStream:NSInputStream? - private var outputStream:NSOutputStream? + fileprivate var inputStream: InputStream? + fileprivate var outputStream: OutputStream? internal var delegate: MQTTSessionStreamDelegate? @@ -31,83 +31,84 @@ class MQTTSessionStream: NSObject, NSStreamDelegate { } func createStreamConnection() { - NSStream.getStreamsToHostWithName(host, port: NSInteger(port), inputStream: &inputStream, outputStream: &outputStream) + Stream.getStreamsToHost(withName: host, port: Int(port), inputStream: &inputStream, outputStream: &outputStream) inputStream?.delegate = self outputStream?.delegate = self - inputStream?.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) - outputStream?.scheduleInRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) + inputStream?.schedule(in: .current, forMode: .defaultRunLoopMode) + outputStream?.schedule(in: .current, forMode: .defaultRunLoopMode) inputStream?.open() outputStream?.open() if ssl { - inputStream?.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey) - outputStream?.setProperty(NSStreamSocketSecurityLevelNegotiatedSSL, forKey: NSStreamSocketSecurityLevelKey) + let securityLevel = StreamSocketSecurityLevel.negotiatedSSL.rawValue + inputStream?.setProperty(securityLevel, forKey: Stream.PropertyKey.socketSecurityLevelKey) + outputStream?.setProperty(securityLevel, forKey: Stream.PropertyKey.socketSecurityLevelKey) } } func closeStreams() { inputStream?.close() - inputStream?.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) + inputStream?.remove(from: .current, forMode: .defaultRunLoopMode) outputStream?.close() - outputStream?.removeFromRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) + outputStream?.remove(from: .current, forMode: .defaultRunLoopMode) } - func sendPacket(packet: MQTTPacket) -> NSInteger { + func send(_ packet: MQTTPacket) -> Int { let networkPacket = packet.networkPacket() - if let writtenLength = outputStream?.write(UnsafePointer(networkPacket.bytes), maxLength: networkPacket.length) { + var bytes = [UInt8](repeating: 0, count: networkPacket.count) + networkPacket.copyBytes(to: &bytes, count: networkPacket.count) + if let writtenLength = outputStream?.write(bytes, maxLength: networkPacket.count) { return writtenLength; } return -1 } - internal func stream(aStream: NSStream, handleEvent eventCode: NSStreamEvent) { + internal func stream(_ aStream: Stream, handle eventCode: Stream.Event) { switch eventCode { - case NSStreamEvent.None: break - case NSStreamEvent.OpenCompleted: break - case NSStreamEvent.HasBytesAvailable: + case Stream.Event(): break + case Stream.Event.openCompleted: break + case Stream.Event.hasBytesAvailable: if aStream == inputStream { - self.receiveDataOnStream(aStream) + receiveDataOnStream(aStream) } - case NSStreamEvent.ErrorOccurred: - self.closeStreams() - self.delegate?.streamErrorOccurred(self) - case NSStreamEvent.EndEncountered: - self.closeStreams() - case NSStreamEvent.HasSpaceAvailable: break + case Stream.Event.errorOccurred: + closeStreams() + delegate?.mqttErrorOccurred(in: self) + case Stream.Event.endEncountered: + closeStreams() + case Stream.Event.hasSpaceAvailable: break default: print("unknown") } } - private func receiveDataOnStream(stream: NSStream) { - - var headerByte = [UInt8](count: 1, repeatedValue: 0) - let len = inputStream?.read(&headerByte, maxLength: 1) - if !(len > 0) { return; } + fileprivate func receiveDataOnStream(_ stream: Stream) { + var headerByte = [UInt8](repeating: 0, count: 1) + guard let len = inputStream?.read(&headerByte, maxLength: 1), len > 0 else { return } let header = MQTTPacketFixedHeader(networkByte: headerByte[0]) - ///Max Length is 2^28 = 268,435,455 (256 MB) + // Max Length is 2^28 = 268,435,455 (256 MB) var multiplier = 1 var value = 0 var encodedByte: UInt8 = 0 repeat { - var readByte = [UInt8](count: 1, repeatedValue: 0) + var readByte = [UInt8](repeating: 0, count: 1) inputStream?.read(&readByte, maxLength: 1) encodedByte = readByte[0] value += (Int(encodedByte) & 127) * multiplier multiplier *= 128 if multiplier > 128*128*128 { - return; + return } } while ((Int(encodedByte) & 128) != 0) let totalLength = value - var responseData: NSData = NSData() + var responseData = Data() if totalLength > 0 { - var buffer = [UInt8](count: totalLength, repeatedValue: 0) + var buffer = [UInt8](repeating: 0, count: totalLength) let readLength = inputStream?.read(&buffer, maxLength: buffer.count) - responseData = NSData(bytes: buffer, length: readLength!) + responseData = Data(bytes: UnsafePointer(buffer), count: readLength!) } - self.delegate?.receivedData(self, data: responseData, withMQTTHeader: header) + delegate?.mqttReceived(responseData, header: header, in: self) } -} \ No newline at end of file +} diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTConnAckPacket.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTConnAckPacket.swift index 25af2f4..1ec9639 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTConnAckPacket.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTConnAckPacket.swift @@ -11,16 +11,12 @@ import Foundation class MQTTConnAckPacket: MQTTPacket { let sessionPresent: Bool - let response: MQTTConnackResponse + let response: MQTTConnAckResponse - init(header: MQTTPacketFixedHeader, networkData: NSData) { - //FIXME: fix - var buffer = [UInt8](count: 2, repeatedValue: 0) - networkData.getBytes(&buffer, range: NSMakeRange(0, 2)) - - self.sessionPresent = (buffer[0] & 0x01) == 0x01 - self.response = MQTTConnackResponse(rawValue: buffer[1])! + init(header: MQTTPacketFixedHeader, networkData: Data) { + sessionPresent = (networkData[0] & 0x01) == 0x01 + response = MQTTConnAckResponse(rawValue: networkData[1])! super.init(header: header) } -} \ No newline at end of file +} diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTConnectPacket.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTConnectPacket.swift index d53186a..5962bde 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTConnectPacket.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTConnectPacket.swift @@ -18,7 +18,7 @@ class MQTTConnectPacket: MQTTPacket { var username: String? = nil var password: String? = nil - var willMessage: MQTTPubMsg? = nil + var lastWillMessage: MQTTPubMsg? = nil init(clientID: String, cleanSession: Bool, keepAlive: UInt16) { self.protocolName = "MQTT" @@ -26,66 +26,58 @@ class MQTTConnectPacket: MQTTPacket { self.cleanSession = cleanSession self.keepAlive = keepAlive self.clientID = clientID - super.init(header: MQTTPacketFixedHeader(packetType: .Connect, flags: 0)) + super.init(header: MQTTPacketFixedHeader(packetType: .connect, flags: 0)) } func encodedConnectFlags() -> UInt8 { var flags = UInt8(0) - if(self.cleanSession) { + if cleanSession { flags |= 0x02 } - if let willMessage = self.willMessage { + if let message = lastWillMessage { flags |= 0x04 - if willMessage.retain { + if message.retain { flags |= 0x20 } - let qos = UInt8(willMessage.QoS.rawValue) + let qos = message.QoS.rawValue flags |= qos << 3 } - if let _ = self.username { + if username != nil { flags |= 0x80 } - if let _ = self.password { + if password != nil { flags |= 0x40 } return flags } - override func networkPacket() -> NSData { - //Variable Header - let variableHeader = NSMutableData() - //Protocol Name - variableHeader.mqtt_appendString(self.protocolName) - //Protocol Level - variableHeader.mqtt_appendUInt8(self.protocolLevel) - //Connect Flags - variableHeader.mqtt_appendUInt8(self.encodedConnectFlags()) - //Keep Alive - variableHeader.mqtt_appendUInt16(self.keepAlive) + override func networkPacket() -> Data { - //Payload - let payload = NSMutableData() - //Client ID - payload.mqtt_appendString(self.clientID) - //Will Packet - if let willMessage = self.willMessage { - payload.mqtt_appendString(willMessage.topic) - payload.mqtt_appendData(willMessage.message) + var variableHeader = Data() + variableHeader.mqtt_append(protocolName) + variableHeader.mqtt_append(protocolLevel) + variableHeader.mqtt_append(encodedConnectFlags()) + variableHeader.mqtt_append(keepAlive) + + var payload = Data() + payload.mqtt_append(clientID) + + if let message = lastWillMessage { + payload.mqtt_append(message.topic) + payload.mqtt_append(message.payload) } - //Username - if let username = self.username { - payload.mqtt_appendString(username) + if let username = username { + payload.mqtt_append(username) } - ///Password - if let password = self.password { - payload.mqtt_appendString(password) + if let password = password { + payload.mqtt_append(password) } - return self.finalPacket(variableHeader, payload: payload) + return finalPacket(variableHeader, payload: payload) } -} \ No newline at end of file +} diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTDisconnectPacket.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTDisconnectPacket.swift index dc3a9b6..725d4e9 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTDisconnectPacket.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTDisconnectPacket.swift @@ -11,10 +11,10 @@ import Foundation class MQTTDisconnectPacket: MQTTPacket { init() { - super.init(header: MQTTPacketFixedHeader(packetType: MQTTPacketType.Disconnect, flags: 0)) + super.init(header: MQTTPacketFixedHeader(packetType: .disconnect, flags: 0)) } - override func networkPacket() -> NSData { - return self.finalPacket(NSData(), payload: NSData()) + override func networkPacket() -> Data { + return finalPacket(Data(), payload: Data()) } } diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTPacket.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTPacket.swift index ed5698a..2a42a16 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTPacket.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTPacket.swift @@ -15,22 +15,22 @@ class MQTTPacket { init(header: MQTTPacketFixedHeader) { self.header = header } - - func networkPacket() -> NSData { - //To be implemented in subclasses - return NSData() + + func networkPacket() -> Data { + // To be implemented in subclasses + return Data() } - //Creates the actual packet to be sent using fixed header, variable header and payload - //Automatically encodes remaining length - func finalPacket(variableHeader: NSData, payload: NSData) -> NSData { - let remainingData = NSMutableData(data: variableHeader) - remainingData.appendData(payload) + // Creates the actual packet to be sent using fixed header, variable header and payload + // Automatically encodes remaining length + func finalPacket(_ variableHeader: Data, payload: Data) -> Data { + var remainingData = variableHeader + remainingData.append(payload) - let finalPacket = NSMutableData() - finalPacket.appendData(self.header.networkPacket()) - finalPacket.mqtt_encodeRemainingLength(remainingData.length) //Remaining Length - finalPacket.appendData(remainingData) //Remaining Data = Variable Header + Payload + var finalPacket = Data() + finalPacket.append(header.networkPacket()) + finalPacket.mqtt_encodeRemaining(length: remainingData.count) // Remaining Length + finalPacket.append(remainingData) // Remaining Data = Variable Header + Payload return finalPacket } diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTPacketFixedHeader.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTPacketFixedHeader.swift index f43ad22..a8db357 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTPacketFixedHeader.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTPacketFixedHeader.swift @@ -19,13 +19,13 @@ class MQTTPacketFixedHeader { } init(networkByte: UInt8) { - self.packetType = MQTTPacketType(rawValue: networkByte >> 4)! - self.flags = networkByte & 0x0F + packetType = MQTTPacketType(rawValue: networkByte >> 4)! + flags = networkByte & 0x0F } - func networkPacket() -> NSData { + func networkPacket() -> Data { var fixedHeaderFirstByte = UInt8(0) - fixedHeaderFirstByte = (0x0F & flags) | (self.packetType.rawValue << 4) - return NSData(bytes: &fixedHeaderFirstByte, length: 1) + fixedHeaderFirstByte = (0x0F & flags) | (packetType.rawValue << 4) + return Data(bytes: &fixedHeaderFirstByte, count: 1) } } diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTPingPacket.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTPingPacket.swift index 5511968..5d28703 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTPingPacket.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTPingPacket.swift @@ -9,10 +9,12 @@ import Foundation class MQTTPingPacket: MQTTPacket { + init() { - super.init(header: MQTTPacketFixedHeader(packetType: MQTTPacketType.PingReq, flags: 0)) + super.init(header: MQTTPacketFixedHeader(packetType: MQTTPacketType.pingReq, flags: 0)) } - override func networkPacket() -> NSData { - return self.finalPacket(NSData(), payload: NSData()) + + override func networkPacket() -> Data { + return finalPacket(Data(), payload: Data()) } } diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTPingResp.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTPingResp.swift index 8bee582..43b612a 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTPingResp.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTPingResp.swift @@ -9,7 +9,8 @@ import Foundation class MQTTPingResp: MQTTPacket { + override init(header: MQTTPacketFixedHeader) { super.init(header: header) } -} \ No newline at end of file +} diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTPubAck.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTPubAck.swift index b7d7717..00636c9 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTPubAck.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTPubAck.swift @@ -9,24 +9,26 @@ import Foundation class MQTTPubAck: MQTTPacket { + let messageID: UInt16 init(messageID: UInt16) { self.messageID = messageID - super.init(header: MQTTPacketFixedHeader(packetType: MQTTPacketType.PubAck, flags: 0)) + super.init(header: MQTTPacketFixedHeader(packetType: MQTTPacketType.pubAck, flags: 0)) } - override func networkPacket() -> NSData { - //Variable Header - let variableHeader = NSMutableData() - variableHeader.mqtt_appendUInt16(self.messageID) + override func networkPacket() -> Data { + // Variable Header + var variableHeader = Data() + variableHeader.mqtt_append(messageID) - return self.finalPacket(variableHeader, payload: NSData()) + return finalPacket(variableHeader, payload: Data()) } - init(header: MQTTPacketFixedHeader, networkData: NSData) { - let buffer = UnsafePointer(networkData.bytes) - self.messageID = (UInt16(buffer[0]) * UInt16(256)) + UInt16(buffer[1]) + init(header: MQTTPacketFixedHeader, networkData: Data) { + + messageID = (UInt16(networkData[0]) * UInt16(256)) + UInt16(networkData[1]) + super.init(header: header) } -} \ No newline at end of file +} diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTPubMsg.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTPubMsg.swift index a536127..c66b565 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTPubMsg.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTPubMsg.swift @@ -8,15 +8,16 @@ import Foundation -public class MQTTPubMsg { - public let topic: String - public let message: NSData - public let retain: Bool - public let QoS: MQTTQoS +open class MQTTPubMsg { - public init(topic: String, message: NSData, retain: Bool, QoS: MQTTQoS) { + open let topic: String + open let payload: Data + open let retain: Bool + open let QoS: MQTTQoS + + public init(topic: String, payload: Data, retain: Bool, QoS: MQTTQoS) { self.topic = topic - self.message = message + self.payload = payload self.retain = retain self.QoS = QoS } diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTPublishPacket.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTPublishPacket.swift index 6e281be..9d84ac9 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTPublishPacket.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTPublishPacket.swift @@ -9,16 +9,17 @@ import Foundation class MQTTPublishPacket: MQTTPacket { + let messageID: UInt16 let message: MQTTPubMsg init(messageID: UInt16, message: MQTTPubMsg) { self.messageID = messageID self.message = message - super.init(header: MQTTPacketFixedHeader(packetType: .Publish, flags: MQTTPublishPacket.fixedHeaderFlagsForMessage(message))) + super.init(header: MQTTPacketFixedHeader(packetType: .publish, flags: MQTTPublishPacket.fixedHeaderFlags(for: message))) } - class func fixedHeaderFlagsForMessage(message: MQTTPubMsg) -> UInt8 { + class func fixedHeaderFlags(for message: MQTTPubMsg) -> UInt8 { var flags = UInt8(0) if message.retain { flags |= 0x08 @@ -27,45 +28,36 @@ class MQTTPublishPacket: MQTTPacket { return flags } - override func networkPacket() -> NSData { - //Variable Header - let variableHeader = NSMutableData() - variableHeader.mqtt_appendString(self.message.topic) - if self.message.QoS != .AtMostOnce { - variableHeader.mqtt_appendUInt16(self.messageID) + override func networkPacket() -> Data { + // Variable Header + var variableHeader = Data() + variableHeader.mqtt_append(message.topic) + if message.QoS != .atMostOnce { + variableHeader.mqtt_append(messageID) } - - //Payload - let payload = self.message.message - return self.finalPacket(variableHeader, payload: payload) + // Payload + let payload = message.payload + return finalPacket(variableHeader, payload: payload) } - init(header: MQTTPacketFixedHeader, networkData: NSData) { - - var readingData = networkData + init(header: MQTTPacketFixedHeader, networkData: Data) { - var bytes = UnsafePointer(readingData.bytes) - let topicLength = 256 * Int(bytes[0]) + Int(bytes[1]) - let topic = NSString(data: readingData.subdataWithRange(NSMakeRange(2, topicLength)), encoding: NSUTF8StringEncoding) as! String - - readingData = readingData.subdataWithRange(NSMakeRange(2+topicLength, readingData.length - topicLength-2)) + let topicLength = 256 * Int(networkData[0]) + Int(networkData[1]) + let topicData = networkData.subdata(in: 2..(readingData.bytes) - self.messageID = 256 * UInt16(bytes[0]) + UInt16(bytes[1]) - readingData = readingData.subdataWithRange(NSMakeRange(2, readingData.length - 2)) //because we read two bytes - + if qos != .atMostOnce { + messageID = 256 * UInt16(payload[0]) + UInt16(payload[1]) + payload = payload.subdata(in: 2..(networkData.bytes) - self.messageID = (UInt16(buffer[0]) * UInt16(256)) + UInt16(buffer[1]) + init(header: MQTTPacketFixedHeader, networkData: Data) { + messageID = (UInt16(networkData[0]) * UInt16(256)) + UInt16(networkData[1]) super.init(header: header) } -} \ No newline at end of file +} diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTSubPacket.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTSubPacket.swift index 4c708f2..caaaa46 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTSubPacket.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTSubPacket.swift @@ -13,26 +13,26 @@ class MQTTSubPacket: MQTTPacket { let topics: [String: MQTTQoS] let messageID: UInt16 - init(topics: [String : MQTTQoS], messageID: UInt16) { + init(topics: [String: MQTTQoS], messageID: UInt16) { self.topics = topics self.messageID = messageID - super.init(header: MQTTPacketFixedHeader(packetType: .Subscribe, flags: 0x02)) + super.init(header: MQTTPacketFixedHeader(packetType: .subscribe, flags: 0x02)) } - override func networkPacket() -> NSData { - //Variable Header - let variableHeader = NSMutableData() - variableHeader.mqtt_appendUInt16(self.messageID) + override func networkPacket() -> Data { + // Variable Header + var variableHeader = Data() + variableHeader.mqtt_append(messageID) - //Payload - let payload = NSMutableData() + // Payload + var payload = Data() - for (key, value) in self.topics { - payload.mqtt_appendString(key) + for (key, value) in topics { + payload.mqtt_append(key) let qos = value.rawValue & 0x03 - payload.mqtt_appendUInt8(qos) + payload.mqtt_append(qos) } - return self.finalPacket(variableHeader, payload: payload) + return finalPacket(variableHeader, payload: payload) } } diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTUnSubAckPacket.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTUnSubAckPacket.swift index e23e4c1..785d730 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTUnSubAckPacket.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTUnSubAckPacket.swift @@ -9,10 +9,11 @@ import Foundation class MQTTUnSubAckPacket: MQTTPacket { + let messageID: UInt16 - init(header: MQTTPacketFixedHeader, networkData: NSData) { - let buffer = UnsafePointer(networkData.bytes) - self.messageID = (UInt16(buffer[0]) * UInt16(256)) + UInt16(buffer[1]) + + init(header: MQTTPacketFixedHeader, networkData: Data) { + messageID = (UInt16(networkData[0]) * UInt16(256)) + UInt16(networkData[1]) super.init(header: header) } -} \ No newline at end of file +} diff --git a/SwiftMQTT/SwiftMQTT/Models/MQTTUnsubPacket.swift b/SwiftMQTT/SwiftMQTT/Models/MQTTUnsubPacket.swift index 28b4514..46d49b2 100644 --- a/SwiftMQTT/SwiftMQTT/Models/MQTTUnsubPacket.swift +++ b/SwiftMQTT/SwiftMQTT/Models/MQTTUnsubPacket.swift @@ -16,19 +16,19 @@ class MQTTUnsubPacket: MQTTPacket { init(topics: [String], messageID: UInt16) { self.topics = topics self.messageID = messageID - super.init(header: MQTTPacketFixedHeader(packetType: .UnSubscribe, flags: 0x02)) + super.init(header: MQTTPacketFixedHeader(packetType: .unSubscribe, flags: 0x02)) } - override func networkPacket() -> NSData { - //Variable Header - let variableHeader = NSMutableData() - variableHeader.mqtt_appendUInt16(self.messageID) + override func networkPacket() -> Data { + // Variable Header + var variableHeader = Data() + variableHeader.mqtt_append(messageID) - //Payload - let payload = NSMutableData() - for topic in self.topics { - payload.mqtt_appendString(topic) + // Payload + var payload = Data() + for topic in topics { + payload.mqtt_append(topic) } - return self.finalPacket(variableHeader, payload: payload) + return finalPacket(variableHeader, payload: payload) } -} \ No newline at end of file +} diff --git a/SwiftMQTT/SwiftMQTTTests/SwiftMQTTTests.swift b/SwiftMQTT/SwiftMQTTTests/SwiftMQTTTests.swift index a7e5330..61a6b15 100644 --- a/SwiftMQTT/SwiftMQTTTests/SwiftMQTTTests.swift +++ b/SwiftMQTT/SwiftMQTTTests/SwiftMQTTTests.swift @@ -16,7 +16,8 @@ class SwiftMQTTTests: XCTestCase, MQTTSessionDelegate { override func setUp() { super.setUp() - mqttSession = MQTTSession(host: "localhost", port: 1883, clientID: "swift", cleanSession: true, keepAlive: 15, useSSL: false) + + mqttSession = MQTTSession(host: "localhost", port: 1883, clientID: "swift", cleanSession: true, keepAlive: 15) mqttSession.delegate = self mqttSession.connect { (succeeded, error) -> Void in XCTAssertTrue(succeeded, "could not connect, error \(error)") @@ -30,102 +31,105 @@ class SwiftMQTTTests: XCTestCase, MQTTSessionDelegate { func testSuccessfulConnection() { mqttSession.disconnect() - let expectation = expectationWithDescription("Connection Establishment") + let expectation = self.expectation(description: "Connection Establishment") mqttSession.connect { XCTAssertTrue($0, "could not connect, error \($1)") expectation.fulfill() } - waitForExpectationsWithTimeout(5) { error in + waitForExpectations(timeout: 5) { error in if let error = error { - print("Error: \(error.localizedDescription)") + print("Error:", error.localizedDescription) } } } func testSubscribe() { - let expectation = expectationWithDescription("Subscribe") - mqttSession.subscribe("/hey/cool", qos: MQTTQoS.AtLeastOnce) { (succeeded, error) -> Void in + let expectation = self.expectation(description: "Subscribe") + + mqttSession.subscribe(to: "/hey/cool", delivering: .atLeastOnce) { (succeeded, error) -> Void in XCTAssertTrue(succeeded, "could not connect, error \(error)") expectation.fulfill() } - waitForExpectationsWithTimeout(5) { error in + waitForExpectations(timeout: 5) { error in if let error = error { - print("Error: \(error.localizedDescription)") + print("Error:", error.localizedDescription) } } } func testMultiSubscribe() { let channels = [ - "/#" : MQTTQoS.AtLeastOnce, - "/yo/sup" : MQTTQoS.AtMostOnce, - "/yo/ok" : MQTTQoS.ExactlyOnce, + "/#": MQTTQoS.atLeastOnce, + "/yo/sup": MQTTQoS.atMostOnce, + "/yo/ok": MQTTQoS.exactlyOnce, ] - let expectation = expectationWithDescription("Multi Subscribe") - mqttSession.subscribe(channels) { (succeeded, error) -> Void in + let expectation = self.expectation(description: "Multi Subscribe") + mqttSession.subscribe(to: channels) { (succeeded, error) -> Void in XCTAssertTrue(succeeded, "could not connect, error \(error)") expectation.fulfill() } - waitForExpectationsWithTimeout(5) { error in + waitForExpectations(timeout: 5) { error in if let error = error { - print("Error: \(error.localizedDescription)") + print("Error:", error.localizedDescription) } } } func testUnSubscribe() { - let expectation = expectationWithDescription("unSubscribe") - mqttSession.unSubscribe(["/hey/cool", "/no/ok"]) { (succeeded, error) -> Void in + let expectation = self.expectation(description: "unSubscribe") + mqttSession.unSubscribe(from: ["/hey/cool", "/no/ok"]) { (succeeded, error) -> Void in XCTAssertTrue(succeeded, "could not connect, error \(error)") expectation.fulfill() } - waitForExpectationsWithTimeout(5) { error in + waitForExpectations(timeout: 5) { error in if let error = error { - print("Error: \(error.localizedDescription)") + print("Error:", error.localizedDescription) } } } func testMultiUnSubscribe() { - let expectation = expectationWithDescription("Multi unSubscribe") - mqttSession.unSubscribe("/hey/cool") { (succeeded, error) -> Void in + let expectation = self.expectation(description: "Multi unSubscribe") + mqttSession.unSubscribe(from: "/hey/cool") { (succeeded, error) -> Void in XCTAssertTrue(succeeded, "could not connect, error \(error)") expectation.fulfill() } - waitForExpectationsWithTimeout(5) { error in + waitForExpectations(timeout: 5) { error in if let error = error { - print("Error: \(error.localizedDescription)") + print("Error:", error.localizedDescription) } } } func testPublishData() { - let expectation = expectationWithDescription("Publish") + let expectation = self.expectation(description: "Publish") let jsonDict = ["hey" : "sup"] - let data = try! NSJSONSerialization.dataWithJSONObject(jsonDict, options: NSJSONWritingOptions.PrettyPrinted) + let data = try! JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted) - mqttSession.publishData(data, onTopic: "/hey/wassap", withQoS: MQTTQoS.AtLeastOnce, shouldRetain: false) { (succeeded, error) -> Void in + mqttSession.publish(data, in: "/hey/wassap", delivering: .atLeastOnce, retain: false) { (succeeded, error) -> Void in XCTAssertTrue(succeeded, "could not connect, error \(error)") expectation.fulfill() } - waitForExpectationsWithTimeout(5) { error in + waitForExpectations(timeout: 5) { error in if let error = error { - print("Error: \(error.localizedDescription)") + print("Error:", error.localizedDescription) } } } + + // MARK: MQTTSessionProtocol - //MARK: MQTT Protocols - func mqttSession(session: MQTTSession, didReceiveMessage message: NSData, onTopic topic: String) { - let stringData = NSString(data: message, encoding: NSUTF8StringEncoding) as! String - print("data received on topic \(topic) message \(stringData)") + func mqttDidReceive(message data: Data, in topic: String, from session: MQTTSession) { + let stringData = String(data: data, encoding: .utf8) + print("received:", stringData, "in:", topic) } - func socketErrorOccurred(session: MQTTSession) { - + func mqttDidDisconnect(session: MQTTSession) { + print("did disconnect") } - func didDisconnectSession(session: MQTTSession) { - + func mqttSocketErrorOccurred(session: MQTTSession) { + print("socket error") } + } diff --git a/SwiftMQTTExample/SwiftMQTTExample.xcodeproj/project.pbxproj b/SwiftMQTTExample/SwiftMQTTExample.xcodeproj/project.pbxproj index dd6d537..bcc8fd1 100644 --- a/SwiftMQTTExample/SwiftMQTTExample.xcodeproj/project.pbxproj +++ b/SwiftMQTTExample/SwiftMQTTExample.xcodeproj/project.pbxproj @@ -12,39 +12,23 @@ 5471A8C21BF228A50079610F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5471A8C01BF228A50079610F /* Main.storyboard */; }; 5471A8C41BF228A50079610F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5471A8C31BF228A50079610F /* Assets.xcassets */; }; 5471A8C71BF228A50079610F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5471A8C51BF228A50079610F /* LaunchScreen.storyboard */; }; - 5471A8D91BF228F40079610F /* SwiftMQTT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5471A8D41BF228E60079610F /* SwiftMQTT.framework */; }; - 5471A8DB1BF228FC0079610F /* SwiftMQTT.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 5471A8D41BF228E60079610F /* SwiftMQTT.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ - 5471A8D31BF228E60079610F /* PBXContainerItemProxy */ = { + 915991A21D8A7CCA00262EC0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 5471A8CE1BF228E50079610F /* SwiftMQTT.xcodeproj */; proxyType = 2; remoteGlobalIDString = 5471A8961BF228900079610F; remoteInfo = SwiftMQTT; }; - 5471A8D51BF228E60079610F /* PBXContainerItemProxy */ = { + 915991A41D8A7CCA00262EC0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 5471A8CE1BF228E50079610F /* SwiftMQTT.xcodeproj */; proxyType = 2; remoteGlobalIDString = 5471A8A01BF228900079610F; remoteInfo = SwiftMQTTTests; }; - 5471A8D71BF228F00079610F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5471A8CE1BF228E50079610F /* SwiftMQTT.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 5471A8951BF228900079610F; - remoteInfo = SwiftMQTT; - }; - 5471A8DC1BF228FC0079610F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 5471A8CE1BF228E50079610F /* SwiftMQTT.xcodeproj */; - proxyType = 1; - remoteGlobalIDString = 5471A8951BF228900079610F; - remoteInfo = SwiftMQTT; - }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -54,7 +38,6 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( - 5471A8DB1BF228FC0079610F /* SwiftMQTT.framework in Embed Frameworks */, ); name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; @@ -77,7 +60,6 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 5471A8D91BF228F40079610F /* SwiftMQTT.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -91,6 +73,7 @@ 5471A8BA1BF228A50079610F /* Products */, ); sourceTree = ""; + usesTabs = 0; }; 5471A8BA1BF228A50079610F /* Products */ = { isa = PBXGroup; @@ -114,11 +97,11 @@ path = SwiftMQTTExample; sourceTree = ""; }; - 5471A8CF1BF228E50079610F /* Products */ = { + 9159919E1D8A7CCA00262EC0 /* Products */ = { isa = PBXGroup; children = ( - 5471A8D41BF228E60079610F /* SwiftMQTT.framework */, - 5471A8D61BF228E60079610F /* SwiftMQTTTests.xctest */, + 915991A31D8A7CCA00262EC0 /* SwiftMQTT.framework */, + 915991A51D8A7CCA00262EC0 /* SwiftMQTTTests.xctest */, ); name = Products; sourceTree = ""; @@ -138,8 +121,6 @@ buildRules = ( ); dependencies = ( - 5471A8D81BF228F00079610F /* PBXTargetDependency */, - 5471A8DD1BF228FC0079610F /* PBXTargetDependency */, ); name = SwiftMQTTExample; productName = SwiftMQTTExample; @@ -153,11 +134,12 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0710; - LastUpgradeCheck = 0710; + LastUpgradeCheck = 0800; ORGANIZATIONNAME = Ankit; TargetAttributes = { 5471A8B81BF228A50079610F = { CreatedOnToolsVersion = 7.1; + LastSwiftMigration = 0800; }; }; }; @@ -174,7 +156,7 @@ projectDirPath = ""; projectReferences = ( { - ProductGroup = 5471A8CF1BF228E50079610F /* Products */; + ProductGroup = 9159919E1D8A7CCA00262EC0 /* Products */; ProjectRef = 5471A8CE1BF228E50079610F /* SwiftMQTT.xcodeproj */; }, ); @@ -186,18 +168,18 @@ /* End PBXProject section */ /* Begin PBXReferenceProxy section */ - 5471A8D41BF228E60079610F /* SwiftMQTT.framework */ = { + 915991A31D8A7CCA00262EC0 /* SwiftMQTT.framework */ = { isa = PBXReferenceProxy; fileType = wrapper.framework; path = SwiftMQTT.framework; - remoteRef = 5471A8D31BF228E60079610F /* PBXContainerItemProxy */; + remoteRef = 915991A21D8A7CCA00262EC0 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; - 5471A8D61BF228E60079610F /* SwiftMQTTTests.xctest */ = { + 915991A51D8A7CCA00262EC0 /* SwiftMQTTTests.xctest */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; path = SwiftMQTTTests.xctest; - remoteRef = 5471A8D51BF228E60079610F /* PBXContainerItemProxy */; + remoteRef = 915991A41D8A7CCA00262EC0 /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXReferenceProxy section */ @@ -227,19 +209,6 @@ }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - 5471A8D81BF228F00079610F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = SwiftMQTT; - targetProxy = 5471A8D71BF228F00079610F /* PBXContainerItemProxy */; - }; - 5471A8DD1BF228FC0079610F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - name = SwiftMQTT; - targetProxy = 5471A8DC1BF228FC0079610F /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - /* Begin PBXVariantGroup section */ 5471A8C01BF228A50079610F /* Main.storyboard */ = { isa = PBXVariantGroup; @@ -273,11 +242,12 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -301,6 +271,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -317,11 +288,12 @@ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; @@ -337,6 +309,8 @@ IPHONEOS_DEPLOYMENT_TARGET = 9.1; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 3.0; VALIDATE_PRODUCT = YES; }; name = Release; @@ -350,6 +324,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.ankit.SwiftMQTTExample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Debug; }; @@ -362,6 +337,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = im.ankit.SwiftMQTTExample; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; }; name = Release; }; diff --git a/SwiftMQTTExample/SwiftMQTTExample/AppDelegate.swift b/SwiftMQTTExample/SwiftMQTTExample/AppDelegate.swift index dd974df..11dd27f 100644 --- a/SwiftMQTTExample/SwiftMQTTExample/AppDelegate.swift +++ b/SwiftMQTTExample/SwiftMQTTExample/AppDelegate.swift @@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/SwiftMQTTExample/SwiftMQTTExample/Base.lproj/Main.storyboard b/SwiftMQTTExample/SwiftMQTTExample/Base.lproj/Main.storyboard index a98ef9c..77ccdaf 100644 --- a/SwiftMQTTExample/SwiftMQTTExample/Base.lproj/Main.storyboard +++ b/SwiftMQTTExample/SwiftMQTTExample/Base.lproj/Main.storyboard @@ -1,8 +1,9 @@ - + - + + @@ -14,32 +15,27 @@ - + - - - - + @@ -49,33 +45,26 @@ - - - + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. - - - + - - - - + + - - + @@ -85,39 +74,33 @@ - - - + - - - - - + + - - + @@ -130,8 +113,7 @@ - - + diff --git a/SwiftMQTTExample/SwiftMQTTExample/MQTTViewController.swift b/SwiftMQTTExample/SwiftMQTTExample/MQTTViewController.swift index 460d6dc..4c4eb13 100644 --- a/SwiftMQTTExample/SwiftMQTTExample/MQTTViewController.swift +++ b/SwiftMQTTExample/SwiftMQTTExample/MQTTViewController.swift @@ -20,40 +20,40 @@ class MQTTViewController: UIViewController, MQTTSessionDelegate { override func viewDidLoad() { super.viewDidLoad() - self.textView.text = nil - self.establishConnection() - NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShow:", name: UIKeyboardWillShowNotification, object: nil) - NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHide:", name: UIKeyboardWillHideNotification, object: nil) + textView.text = nil + establishConnection() - let tapGesture = UITapGestureRecognizer(target: self, action: "hideKeyboard") - self.view.addGestureRecognizer(tapGesture) + NotificationCenter.default.addObserver(self, selector: #selector(MQTTViewController.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(MQTTViewController.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil) + + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(MQTTViewController.hideKeyboard)) + view.addGestureRecognizer(tapGesture) } func hideKeyboard() { - self.view.endEditing(true) + view.endEditing(true) } - func keyboardWillShow(notification: NSNotification) { - let userInfo = notification.userInfo! as NSDictionary - let kbHeight = userInfo.objectForKey(UIKeyboardFrameBeginUserInfoKey)?.CGRectValue.size.height - self.bottomConstraint.constant = kbHeight! + func keyboardWillShow(_ notification: Notification) { + let userInfo = (notification as NSNotification).userInfo! as NSDictionary + let kbHeight = (userInfo.object(forKey: UIKeyboardFrameBeginUserInfoKey) as! NSValue).cgRectValue.size.height + bottomConstraint.constant = kbHeight } - func keyboardWillHide(notification: NSNotification) { - self.bottomConstraint.constant = 0 + func keyboardWillHide(_ notification: Notification) { + bottomConstraint.constant = 0 } func establishConnection() { - - let host = "192.168.1.131" - let port:UInt16 = 1883 + let host = "localhost" + let port: UInt16 = 1883 let clientID = self.clientID() mqttSession = MQTTSession(host: host, port: port, clientID: clientID, cleanSession: true, keepAlive: 15, useSSL: false) mqttSession.delegate = self - - self.appendStringToTextView("Trying to connect to \(host) on port \(port) for clientID \(clientID)") + appendStringToTextView("Trying to connect to \(host) on port \(port) for clientID \(clientID)") + mqttSession.connect { if !$0 { self.appendStringToTextView("Error Occurred During connection \($1)") @@ -66,7 +66,7 @@ class MQTTViewController: UIViewController, MQTTSessionDelegate { func subscribeToChannel() { let subChannel = "/#" - mqttSession.subscribe(subChannel, qos: MQTTQoS.AtLeastOnce) { + mqttSession.subscribe(to: subChannel, delivering: .atMostOnce) { if !$0 { self.appendStringToTextView("Error Occurred During subscription \($1)") return @@ -75,77 +75,80 @@ class MQTTViewController: UIViewController, MQTTSessionDelegate { } } - func appendStringToTextView(string: String) { - self.textView.text = "\(self.textView.text)\n\(string)" + func appendStringToTextView(_ string: String) { + textView.text = "\(textView.text ?? "")\n\(string)" + let range = NSMakeRange(textView.text.characters.count - 1, 1) + textView.scrollRangeToVisible(range) } - //MARK:- MQTTSessionDelegates + // MARK: - MQTTSessionDelegates - func mqttSession(session: MQTTSession, didReceiveMessage message: NSData, onTopic topic: String) { - let stringData = NSString(data: message, encoding: NSUTF8StringEncoding) as! String - self.appendStringToTextView("data received on topic \(topic) message \(stringData)") + func mqttSession(session: MQTTSession, received message: Data, in topic: String) { + let string = String(data: message, encoding: .utf8)! + appendStringToTextView("data received on topic \(topic) message \(string)") } - func socketErrorOccurred(session: MQTTSession) { - self.appendStringToTextView("Socket Error") + func mqttSocketErrorOccurred(session: MQTTSession) { + appendStringToTextView("Socket Error") } - func didDisconnectSession(session: MQTTSession) { - self.appendStringToTextView("Session Disconnected.") + func mqttDidDisconnect(session: MQTTSession) { + appendStringToTextView("Session Disconnected.") } - //MARK:- IBActions - - @IBAction func resetButtonPressed(sender: AnyObject) { - self.textView.text = nil - self.channelTextField.text = nil - self.messageTextField.text = nil - self.establishConnection() - } + // MARK: - IBActions - @IBAction func sendButtonPressed(sender: AnyObject) { - if self.channelTextField.text?.characters.count > 0 && self.messageTextField.text?.characters.count > 0 { - let channelName = self.channelTextField.text! - let message = self.messageTextField.text! - let messageData = message.dataUsingEncoding(NSUTF8StringEncoding)! - mqttSession.publishData(messageData, onTopic: channelName, withQoS: .AtLeastOnce, shouldRetain: false) { - if !$0 { - self.appendStringToTextView("Error Occurred During Publish \($1)") - return - } - self.appendStringToTextView("Published \(message) on channel \(channelName)") - } - } + @IBAction func resetButtonPressed(_ sender: AnyObject) { + textView.text = nil + channelTextField.text = nil + messageTextField.text = nil + establishConnection() } - //MARK:- Utilities - + @IBAction func sendButtonPressed(_ sender: AnyObject) { + + guard let channel = channelTextField.text, let message = messageTextField.text, + !channel.isEmpty && !message.isEmpty + else { return } + + let data = message.data(using: .utf8)! + mqttSession.publish(data, in: channel, delivering: .atMostOnce, retain: false) { + if !$0 { + self.appendStringToTextView("Error Occurred During Publish \($1)") + return + } + self.appendStringToTextView("Published \(message) on channel \(channel)") + } + } + + // MARK: - Utilities + func clientID() -> String { - let userDefaults = NSUserDefaults.standardUserDefaults() + let userDefaults = UserDefaults.standard let clientIDPersistenceKey = "clientID" - - var clientID = "" - - if let savedClientID = userDefaults.objectForKey(clientIDPersistenceKey) as? String { + let clientID: String + + if let savedClientID = userDefaults.object(forKey: clientIDPersistenceKey) as? String { clientID = savedClientID } else { - clientID = self.randomStringWithLength(5) - userDefaults.setObject(clientID, forKey: clientIDPersistenceKey) + clientID = randomStringWithLength(5) + userDefaults.set(clientID, forKey: clientIDPersistenceKey) userDefaults.synchronize() } return clientID } - //http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift - func randomStringWithLength(len: Int) -> String { - let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - let randomString : NSMutableString = NSMutableString(capacity: len) - for (var i=0; i < len; i++){ - let length = UInt32 (letters.length) + // http://stackoverflow.com/questions/26845307/generate-random-alphanumeric-string-in-swift + func randomStringWithLength(_ len: Int) -> String { + let letters = Array("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789".characters) + + var randomString = String() + for _ in 0..