Upgrading from v12

This guide will help you navigate the changes that were introduced in v13.

What are the big changes?

The biggest change is how to create and manage clients. Much like the native JS client and server, the swift client now only uses one engine per connection. Previously in order to use namespaces it was required to create multiple clients, and each client had its own engine.

Some v12 code might’ve looked like this:

let defaultSocket = SocketIOClient(socketURL: myURL)
let namespaceSocket = SocketIOClient(socketURL: myURL, config: [.nsp("/swift")])

// add handlers for sockets and connect

In v12 this would have opened two connections to the socket.io.

In v13 the same code would look like this:

let manager = SocketManager(socketURL: myURL)
let defaultSocket = manager.defaultSocket
let namespaceSocket = manager.socket(forNamespace: "/swift")

// add handlers for sockets and connect

In v13 defaultSocket and namespaceSocket will share a single transport. This means one less connection to the server needs to be opened.

What might I have to change?

  • The most obvious thing you will need to change is that instead of creating SocketIOClients directly, you will create a SocketManager and either use the defaultSocket property if you don’t need namespaces, or call the socket(forNamespace:) method on the manager.

  • SocketIOClient is no longer a client to an engine. So if you were overriding the engine methods, these have been moved to the manager.

  • The library is now a single target. So you might have to change some of your Xcode project settings.

  • SocketIOClients no longer take a configuration, they are shared from the manager.

  • The joinNamespace() and leaveNamespace() methods on SocketIOClient no longer take any arguments, and in most cases no longer need to be called. Namespace joining/leaving can be managed by calling connect()/disconnect() on the socket associated with that namespace.


What things should I know?

How sockets are stored

You should know that SocketIOClients no longer need to be held around in properties, but the SocketManager should.

One of the most common mistakes people made is not maintaining a strong reference to the client.

class Manager {
    func addHandlers() {
        let socket = SocketIOClient(socketURL: myURL, config: [.nsp("/swift")])

        // Add handlers
    }
}

This would have resulted in the client being released and no handlers being called.

A correct equivalent would be:

class Manager {
    let socketManager = SocketManager(socketURL: someURL)

    func addHandlers() {
        let socket = socketManager.socket(forNamespace: "/swift")

        // Add handlers
    }
}

This code is fine because the SocketManager will maintain a strong reference to the socket.

It’s also worth noting that subsequent calls to socket(forNamespace:) will return the same socket instance as the first call. So you don’t need to hold onto the socket directly just to access it again, just call socket(forNamespace:) on the manager to get it. This does mean that if you need multiple sockets on the same namespace, you will have to use multiple managers.

What to call connect on

Connect can either be called on the manager directly, or on one of the sockets made from it. In either case, if the manager was not already connected to the server, a connection will be made. Also in both cases the default socket (namespace “/”) will fire a connect event.

The difference is that if connect() is just called on the manager, then any sockets for that manager that are not the default socket will not automatically connect. connect() will need to be called individually for each socket. However, if connect() is called on a client, then in addition to opening the connection if needed, the client will connect to its namespace, and a connect event fired.