代表没有设置
我在Swift中构build了一个使用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方法进行设置。
在debugging的时候,我已经validation了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)") } }
这是GCDAsyncSocket和Swift代码内的委托(也可以应用于其他委托scheme)的问题。
你在这里遇到的是:
-
Swift为GCDAsyncSocket()的调用创build一个自引用
-
Objective-C做了一些事情,但把它当作__weak,基本上不会创buildSwift需要关心的额外的参考。
-
Swift完成对GCDAsyncSocket()的调用,ARC删除对self的引用,因为没有其他引用。 Swift不知道Objective-C仍然需要它。
-
而且,由于代表被声明为__weak,所以在Objective-C部分也是如此。
-
GCDAsyncSocket没有委托,并抱怨。
解决scheme:
-
将NSObject作为一个超类添加到Swift类中,然后在你的类中将“self”保留在init()中的某个全局类variables中。 然后ARC看到参考,一切都很好。 这将在对象的生命周期中创build一个Swift端的引用,Objective-C中的__weak将按预期工作。
-
或者从GCDAsyncSocket中删除__weak,并在Swift类的Deinit()方法中添加一个socket.Delegate(nil)。 这将在Objective-C上创build一个引用,防止Swift端的ARC将其解除分配,直到手动完成。
GCDAsyncSocket尝试不泄漏内存。 在一个纯粹的Objective-C项目中,它可以正常工作,但是当从Swift使用Objective-C时,如果在Objective-C中声明为__weak,则需要在Swift端保留委托。