丢失对Swift中实例的属性的引用

时间:2015-01-09 20:35:48

标签: ios swift ios8

我遇到的问题是,我创建的类实例的属性似乎正在失去对其值的引用。

基本上我有一个这样的课程:

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)
        }
    }
}

然后在ViewController中我有以下代码:

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()        
    }
}

ch.callbacks的println中,它显示字典中有一个键值对。

但是,当通道稍后在通过套接字收到消息时收到事件时,回调不再存在。在代码方面,这里是完整的代码:

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]
    }
}

所以基本上当WebSocket收到一些给定通道的数据时,它应该检查事件名称,如果有一个带有该事件名称的回调,则调用与该事件名称相关的回调。但是,调用handleEvent方法时,通道显然没有回调,即使在viewDidLoad的底部,它显示为在通道的callbacks属性中有回调。

关于回调消失的地点/原因的任何想法?

更新

我现在尝试在ch函数之外移动频道channelSetup的定义,所以就像这样,但没有运气:

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()
    }
}

1 个答案:

答案 0 :(得分:1)

我已经解决了这个问题,但并不是因为我在Swift中发生的事情我并不理解。相反,只是我设置代码的方式意味着创建了重复的通道对象,并且回调仅添加到其中一个通道。