2014-07-18 4 views
1

Objective-C로 작성된 GCDAsyncSocket을 사용하는 Swift에서 프레임 워크를 작성합니다.대리자가 설정되지 않음

I 수신하고 오류 : I는, init 메소드의 대리인 (아래 참조)를 설정하려고 또한 초기화 후 setDelegate 방법을 사용하여 설정을 시도

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

.

디버깅 중에 setDelegate 코드가 호출되고 (self) 전달 된 값에 실제로 참조가 포함되어 있는지 확인했습니다.

업데이트 : GCDAsyncSocket.m을 수정하여 대리자 선언에서 __weak 키워드를 제거하면 작동하지만, 왜 그렇게해야하는지 이해할 수 없습니다. , __weak id delegate 클래스 문제 일으키는 여기

id delegate 변경 : 라인였다이 (다른 대리인 시나리오에 적용도 가능) GCDAsyncSocket 및 SWIFT 코드 내부 위임에 문제가

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)") 
    } 
} 
+0

아마도 대리자를 유지하는 것이 없기 때문에 ARC가 대리인을 메모리에서 해제하려고했기 때문일 수 있습니다. '__weak' 문을 제거함으로써 GCDAsyncSocket은 델리게이트를 유지하고 ARC에 의해 해제되지 않습니다. – galrito

+0

그 일은 일어난 것처럼 들리지만, var 소켓의 Server.swift에 의해 유지되어야합니다. – picciano

+0

저는 GCDAsyncSocket에 익숙하지 않지만 클래스의 헤더를 보았습니다. 그리고 대리자 속성은 weak로 선언되어 있기 때문에 유지되지 않습니다. – galrito

답변

3

이다 .

은 당신이 여기에서 발생하는 것은 :

  1. 스위프트가 GCDAsyncSocket()의 호출에 대해 자체에 대한 참조를 생성

  2. 오브젝티브 C는 그것으로 무언가를하지만, 기본적으로 __weak로 취급 추가적인 참고 자료를 만들지 않아야합니다.

  3. Swift는 GCDAsyncSocket()에 대한 호출을 완료하고 ARC는 다른 참조가 없으므로 자체 참조를 제거합니다. Swift는 Objective-C가 여전히 그것을 필요로하는지 알지 못합니다.

  4. 델리게이트가 __weak로 선언되었으므로 Objective-C 부분에서도 사라졌습니다.

  5. GCDAsyncSocket에는 더 이상 대리인이 없으므로 불만을 토로합니다.

솔루션 :

  1. 이 스위프트 클래스에 수퍼 클래스로 NSObject를 추가 한 다음 초기화 내부의 글로벌 클래스 변수에 클래스 내부 "자신을"유지(). 그러면 ARC는 참조를보고 모든 것이 잘됩니다. 이렇게하면 Object의 수명 동안 Swift 측면에 대한 참조가 만들어지고 Objective-C의 __weak이 의도 한대로 작동합니다.

  2. 또는 GCDAsyncSocket에서 __weak을 제거하고 Swift 클래스의 Deinit() 메서드에서 socket.Delegate (nil)을 추가하십시오. 이렇게하면 Objective-C 측면에 참조가 만들어져 수동으로 수행 할 때까지 스위프트 측의 ARC가 해제됩니다.

GCDAsyncSocket은 메모리 누출을 시도하지 않습니다. 순수한 Objective-C 프로젝트에서는 의도 한대로 잘 작동하지만 Objective-C에서 Objective-C를 사용할 때 Objective-C에서 __weak으로 선언 된 경우 Swift 측에서 대리인을 보유해야합니다.

+0

__weak를 제거해도 실제로 문제가 해결되었으므로 정확한 답변을 표시했습니다. 아직도 이해할 수없는 부분은 Server와 그것의'var socket '인스턴스가 deinit 화되지 않고 여전히 활성화되어 있다는 것입니다. 소켓이 델리게이트 집합을 가져 오지 못한다는 것입니다. 줄 단위로 디버깅을하는 경우에도 setDeletage는 계속 표시되지만 오류가 발생하지는 않습니다. – picciano

+0

var 소켓은 GCCDAsyncSocket을 호출 한 결과입니다. 그러나 self()는 매개 변수입니다. GCDAsyncSocket의 결과는 유지되지만 호출 전이나 호출 중에 참조되지 않으므로 호출 중에 사용 된 매개 변수는 유지되지 않습니다. Swift에서 모든 매개 변수는 참조이며 아무것도 전달되지 않고 문제의 근본 원인입니다. 그리고 강력한 참조없이 호출 된 메소드가 완료되면 self()의 결과가 사라집니다. 순수한 Objective-C에서는 자체가 값이 아닌 참조로 전달되므로 작동합니다. – scythe42

+0

Xcode 6.1.1에서는 Swift 클래스를 NSObject의 하위 클래스로 유지함으로써이 문제를 해결할 수있었습니다 (유지할 필요가 없음). –

관련 문제