Swift 3 was released on September 13th 2016. PusherSwift 3.0.0 was released on 14th September 2016. A day late, I know, but in my potentially slightly biased opinion, it was worth waiting those extra 24 hours.

It’s been pointed out to me, on many occasions, that I never wrote a blog post announcing our release of a Swift library. Now we’re at version 3.2.0. So in a move I’m describing as “maximising efficiency” I’m using this blog post to announce PusherSwift to the world, as well its update to version 3.2.0 (although I’ll only really focus on the changes from pre-3.0.0 to 3.0.0). I’ve also written a second post about some of the more technical parts of building a framework that is going to be used by other developers, which will be published soon!

As I wrote in my blog post on why you should learn Swift I’m the office fanboy when it comes to Swift. I won’t rehash that blog post here but the short version is that if you’ve not given Swift a try, you should.

Announcing PusherSwift

So here it is – we have a Pusher client library written in Swift which you can find here in all its glory!

If you’re just interested in the recent changes then you can jump over to the changelog on GitHub.

PusherSwift 3

Normally I’m not one to be too much of a perfectionist but I have a weakness when it comes to Swift. From my point of view, there was always a reason not to put out an announcement.

“I just want to make this part of it nicer before I announce it”.

“Swift 2 is just about to be released so I can’t announce it until at least after that…”.

“I’ve restarted Xcode 8 times and it still won’t build successfully even though it worked fine yesterday!”.

“Well Swift 3 is being released in a couple of weeks so let’s wait for that!”.

They were all pretty terrible reasons not to announce it though (apart from the Xcode one). So let’s crack on with the changes that PusherSwift 3 introduced.

Objective-C interoperability

Perhaps unexpected in a blog post that is ostensibly focussed on Swift but probably the biggest change that PusherSwift 3.0.0 brought was the ability to interface with it using Objective-C.

Apple has some docs about using Swift and Objective-C in tandem. If you’ve ever worked on something that involved interoperability then you’ll know this, but for those that haven’t, it’s not all plain sailing.

At first look, it appeared that we’d be able to add the interoperability with a few well-placed @objc s and some : NSObject s. That gets you surprisingly close, but not all the way. Tucked slightly out of the way in one of Apple’s docs about interacting with Objective-C APIs is a list of Swift types that you cannot use in Objective-C.

Cutting to the chase, the main problem was the lack of Objective-C compatibility with Swift’s structs and enums. These appeared (and still do – I’ll get to it in a moment) in PusherSwift in quite prominent areas. Specifically, when creating a PusherClientOptions object you’re creating a Swift struct and when creating that PusherClientOptions object you’ll likely be using a Swift enum ( AuthMethod , or even PusherHost ).

The decision I took was to keep the nice Swifty feel for those using the library in Swift and to provide a slight variation for those using it in Objective-C. This is best described in examples, starting with a Swift one:

let options = PusherClientOptions( authMethod: .endpoint(authEndpoint: "https://your.authendpoint/pusher/auth") ) let pusher = Pusher(key: "YOUR_APP_KEY", options: options)

and its Objective-C equivalent:

OCAuthMethod *authMethod = [[OCAuthMethod alloc] initWithAuthEndpoint:@"https://your.authendpoint/pusher/auth"]; PusherClientOptions *options = [[PusherClientOptions alloc] initWithAuthMethod:authMethod]; Pusher *pusher = [[Pusher alloc] initWithAppKey:@"YOUR_APP_KEY" options:options];

You can see that the authMethod object in the Objective-C example is of type OCAuthMethod . This is just a Swift class that is able to be used in Objective-C and provides an almost identical API to the Swift version. The downside is that the APIs for the Swift and Objective-C versions are every-so-slightly different in places, but the benefit is that each API feels natural to use in the language it was written for.

Other things like subscribing to channels is a more direct translation. The Swift version is the same as it’s always been:

let myChannel = pusher.subscribe("my-channel")

and the Objective-C variant:

PusherChannel *myChannel = [pusher subscribeWithChannelName:@"my-channel"];

If you’re interested in more specifics about how the Objective-C interoperability works then your best bet is to take a look at the Objective-C.swift file which encapsulates pretty much all of the code that is specific to making the interoperability work well.

Native notifications merge

A few months ago we announced the start of our Mobile Push Notifications API beta. If you’ve not taken a look at this then I suggest that you at least take a look at the link to the product page – it looks great and gives a nice, quick overview of the product.

When the beta began we had libraries ready to work with the new API but they were on specific branches of the respective libraries on GitHub. Now that the API has had some time to settle down and we’ve ironed out those pesky remaining bugs, those feature-specific branches have been merged in. As such, it’s now as easy as this to have a device register for push notifications with Pusher’s Push Notifications API:

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) { pusher.nativePusher().register(deviceToken: deviceToken) pusher.nativePusher().subscribe(interestName: "donuts") }

If you’re interested in seeing how you can get setup with mobile push notifications in your app then head on over to our docs. One of our developers has even spent some time looking into having macOS support for the push notifications part of the library, so stay tuned if that’s something you’re interested in.

Delegate creation

Before 3.0.0 was released the PusherConnection class was loaded with properties for things that were all related to the connection. It didn’t really make sense to keep them so directly tied to the connection object though and so a good chunk of these were removed and instead became part of a new delegate property, of the type PusherConnectionDelegate .

In practical terms that meant that the debugLogger and stateChangeDelegate properties were absorbed by the new delegate, along with two new subscription event delegate functions that can also be optionally implemented.

The delegate on the connection now allows developers the ability to implement any (or all) of the following functions:

func connectionStateDidChange(from old: ConnectionState, to new: ConnectionState) func debugLog(message: String) func subscriptionDidSucceed(channelName: String) func subscriptionDidFail(channelName: String, response: URLResponse?, data: String?, error: NSError?)

Since the 3.0.0 release

There haven’t been too many mention-worthy changes since the 3.0.0 release other than the addition on another optional delegate; this one on the Pusher object itself. This delegate is currently only really responsible for allowing developers to be notified about events that relate to Push Notifications. As such, these are the functions that you can choose to implement in your delegate, should you wish to:

func didRegisterForPushNotifications(clientId: String) func didSubscribeToInterest(named name: String) func didUnsubscribeFromInterest(named name: String)

I imagine that in one of the future release of PusherSwift that the newer PusherDelegate and the PusherConnectionDelegate may well be merged into a single delegate to keep things a bit tidier.

The future

Even with all of the recent changes, there’s more that we’re looking to implement in the library. There are plenty of changes that can be made, all the way from more substantial things like turning the connection state of the underlying websocket into a proper state machine, down to simpler tasks like allowing binding to specific event names at the global level.

If you’re up for the challenge of working on these or any other improvements, don’t hesitate to create a pull request! We’re always more than happy to accept work from people in the community.