代表没有设置

时间:2014-07-18 12:12:55

标签: ios objective-c macos delegates swift

我在Swift中构建一个使用Objective-C编写的GCDAsyncSocket的框架。

我收到的错误是:

Couldn't start socket: Error Domain=GCDAsyncSocketErrorDomain Code=1 "Attempting to accept without a delegate. Set a delegate first." UserInfo=0x61000026b940 {NSLocalizedDescription=Attempting to accept without a delegate. Set a delegate first.}

我尝试在init方法中设置委托(如下所示),并尝试在初始化后使用setDelegate方法设置委托。

在调试时,我已经验证调用了setDelegate代码,并且传入的值(self)实际上包含一个引用。

更新:当我修改GCDAsyncSocket.m以从委托声明中删除__weak关键字时,它可以工作,但我仍然不明白为什么我应该这样做。 该行为:__weak id delegate,更改为id delegate

以下是导致问题的类:

class Server: GCDAsyncSocketDelegate
{
    let boundHost:String?
    let port:UInt16
    var socket:GCDAsyncSocket?

    init(boundHost: String?, port: UInt16)
    {
        if boundHost {
            self.boundHost = boundHost!
        }
        self.port = port

        println("Server created with host: \(self.boundHost) and port: \(self.port).")
    }

    convenience init(port:UInt16) {
        self.init(boundHost: nil, port: port)
    }

    func startServer() -> Bool
    {
        if !socket
        {
            socket = GCDAsyncSocket(delegate: self, delegateQueue: dispatch_get_main_queue())
        }

        var error:NSError?
        if !socket!.acceptOnInterface(boundHost, port: port, error: &error)
        {
            println("Couldn't start socket: \(error)")
            return false;
        }
        else
        {
            println("Listening on \(port).")
            return true
        }
    }

    func stopServer() -> Bool
    {
        if socket
        {
            socket!.disconnect()
            return true
        }
        return false
    }

    func socket(sock:GCDAsyncSocket!, didAcceptNewSocket newSocket:GCDAsyncSocket!)
    {
        println("New socket received: \(newSocket)")
    }
}

1 个答案:

答案 0 :(得分:3)

这是GCDAsyncSocket和Swift代码中的委托的问题(也可以应用于其他委托方案)。

您在这里遇到的是:

  1. Swift为GCDAsyncSocket()的调用创建了对self的引用

  2. Objective-C对它做了些什么,但把它当作__weak来处理,基本上没有创建Swift需要关注的额外引用。

  3. Swift完成对GCDAsyncSocket()的调用,ARC删除对self的引用,因为没有其他引用。 Swift不知道Objective-C仍然需要它。

  4. 当委托被声明为__weak时,它也会在Objective-C部分中消失。

  5. GCDAsyncSocket已经没有委托,并抱怨它。

  6. 解决方案:

    1. 将NSObject作为超类添加到Swift类中,然后在类中保留“self”到init()中的某个全局类变量。然后ARC看到参考,一切都很好。这将在Swift方面为Object的生命周期创建一个引用,Objective-C中的__weak将按预期工作。

    2. 或者从GCDAsyncSocket中删除__weak并在Swift类的Deinit()方法中添加socket.Delegate(nil)。这将在Objective-C端创建一个引用,防止Swift端的ARC将其解除分离,直到您手动执行。

    3. GCDAsyncSocket尝试不泄漏内存。在一个纯粹的Objective-C项目中,这可以正常工作,但是当使用Swift中的Objective-C时,如果它们在Objective-C中声明为__weak,则需要在Swift端保留委托。