Loss of reference to an instance property in Swift

I am facing an issue where a property of an instance of a class I have created seems to lose its reference to its values.

Essentially I have a class like this:

class Channel {    
    var callbacks: [String: (JSON) -> Void]
    var subscribed = false
    let name: String

    init(name: String) {
        self.name = name
        self.callbacks = [:]
    }

    func bind(eventName: String, callback: (JSON) -> Void) {
        self.callbacks[eventName] = callback
    }

    func handleEvent(eventName: String, eventData: String) {
        if let cb = self.callbacks[eventName] {
            let json = JSON(object: eventData)
            cb(json)
        }
    }
}

      

and then inside the ViewController I have the following code:

class ViewController: UIViewController {
    let wSock = wSocket(key: "afa4d38348f89ba9c398")

    func channelSetup() {
        var ch = wSock.subscribe("test-channel")
        ch.bind("test-event", { (data: JSON) -> Void in
            println("I'm the callback getting called")
        })
        println(ch.callbacks)
    }

    override func viewDidLoad() {
        super.viewDidLoad()        

        channelSetup()        
    }
}

      

In println, ch.callbacks

it shows that there are a pair of key values ​​in the dictionary.

However, when the channel receives the event later, when there is a message received over the socket, there is no more callback. In terms of code, here is the complete code:

import UIKit

class ViewController: UIViewController {
    let wSock = wSocketClient(key: "afa4d38348f89ba9c398")

    func channelSetup() {
        var ch = wSock.subscribe("test-channel")
        ch.bind("test-event", { (data: JSON) -> Void in
            println("I'm the callback getting called")
        })
        println(ch.callbacks)
    }

    override func viewDidLoad() {
        super.viewDidLoad()        

        channelSetup()        
    }
}

class wSocketClient {
    let connection: Connection

    init(key: String, encrypted: Bool = false) {
        var url = "SOCKET_URL"
        connection = Connection(url: url)
    }

    func subscribe(channelName: String) -> Channel {
        return self.connection.addChannel(channelName)
    }

    func connect() {
        self.connection.open()
    }
}

class Connection: WebSocketDelegate {
    let url: String
    lazy var socket: WebSocket = { [unowned self] in
        return self.connectInternal()
    }()
    let connected = false
    var channels = Channels()

    init(url: String) {
        self.url = url
    }

    func addChannel(channelName: String) -> Channel {
        return Channel(name: channelName)
    }

    func open() {
        if self.connected {
            return
        } else {
            self.socket = connectInternal()
        }
    }

    func connectInternal() -> WebSocket {
        let ws = WebSocket(url: NSURL(string: self.url)!)
        ws.delegate = self
        ws.connect()
        return ws
    }

    func websocketDidReceiveMessage(text: String) {
        let data = (text as NSString).dataUsingEncoding(NSUTF8StringEncoding)
        let json = JSON(data: data!)

        if let channelName = json["channel"].stringValue {
            if let internalChannel = self.channels.find(channelName) {
                if let eName = json["event"].stringValue {
                    if let eData = json["data"].stringValue {
                        internalChannel.handleEvent(eName, eventData: eData) // this is the part of the code where the channel should eventually call the callback
                    }
                }
            }
        }
    }
}

class Channel {    
    var callbacks: [String: (JSON) -> Void]
    var subscribed = false
    let name: String

    init(name: String) {
        self.name = name
        self.callbacks = [:]
    }

    func bind(eventName: String, callback: (JSON) -> Void) {
        self.callbacks[eventName] = callback
    }

    func handleEvent(eventName: String, eventData: String) {
        if let cb = self.callbacks[eventName] { // here self.callbacks is empty and the callback has disappeared
            let json = JSON(object: eventData)
            cb(json)
        }
    }
}

class Channels {
    var channels = [String: Channel]()

    func add(channelName: String) -> Channel {
        if let channel = self.channels[channelName] {
            return channel
        } else {
            let newChannel = Channel(name: channelName)
            self.channels[channelName] = newChannel
            return newChannel
        }
    }

    func find(channelName: String) -> Channel? {
        return self.channels[channelName]
    }
}

      

So basically, when the WebSocket receives some data for a given channel, it should check for the event name, and if there is a callback with that event name, then call the callback associated with that event name. However, the channel does not appear to have callbacks when the method is called handleEvent

, although at the bottom of the viewDidLoad it appears as having a callback on the property callbacks

for the channel.

Any ideas as to where / why the callback is disappearing?

Update

Now I tried to move the channel definition, ch

outside of the function channelSetup

, to like it, but no luck:

class ViewController: UIViewController {
    let wSock = wSocket(key: "afa4d38348f89ba9c398")
    var ch: Channel = nil

    func channelSetup() {
        ch = wSock.subscribe("test-channel")
        ch.bind("test-event", { (data: JSON) -> Void in
            println("I'm the callback getting called")
        })
        println(ch.callbacks)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        channelSetup()
    }
}

      

+3


source to share


1 answer


I solved it, but not because something was happening in Swift that I didn't understand. Instead, the way that I set the code meant that duplicate channel objects were created and the callback was only added to one of the channels.



+1


source







All Articles