在Swift中实现具有Closure的委托?

时间:2014-06-11 21:51:59

标签: delegates closures swift

假设我正在使用Swift并在框架中调用期望委托的方法。

是否有可能提供一个闭包并在那里内联实现委托?

我希望能够像Java中的匿名类一样使用它。例如:

let cnx:NSURLConnection = NSURLConnection(request: request, delegate: {
     func connection(connection: NSURLConnection!, didReceiveData data: NSData!){
         //append data
     }
     func connectionDidFinishLoading(connection: NSURLConnection){
         //all done
     }
});

2 个答案:

答案 0 :(得分:20)

您无法定义匿名类,但您可以定义一个非常相似的本地类。我实际上已经从内联类方法迁移出来,因为REPL似乎有问题,尽管编译器看起来很好。我现在使用的方法是定义一个胶水类,它将方法转发到init中定义的闭包,所以感觉非常自然。

URLConnectionDataDelegate定义为:

class GreenUrlConnectionDataDelegate: NSObject, NSURLConnectionDataDelegate {
    var didFinishLoading:()->()
    var didReceiveResponse:((NSURLResponse!)->())?
    var didReceiveData:((NSData!)->())?
    var didFailWithError:((NSError!)->())?

    func connectionDidFinishLoading(conn:NSURLConnection!) {
        didFinishLoading()
    }

    func connection(conn:NSURLConnection!, didReceiveResponse response:NSURLResponse!) {
        didReceiveResponse?(response)
    }

    func connection(conn:NSURLConnection!, didReceiveData data:NSData!) {
        didReceiveData?(data)
    }

    func connection(conn:NSURLConnection!, didFailWithError error:NSError!) {
        didFailWithError?(error)
    }

    init(
        didFinishLoading:()->(),
        didReceiveResponse:((NSURLResponse!)->())? = nil,
        didReceiveData:((NSData!)->())? = nil,
        didFailWithError:((NSError!)->())? = nil
    ) {
        self.didFinishLoading = didFinishLoading
        self.didReceiveResponse = didReceiveResponse
        self.didReceiveData = didReceiveData
        self.didFailWithError = didFailWithError
    }
}

这允许我使用内联委托定义一个函数:

func downloadUrl(string:String, completion:(data:NSData?, error:NSError?) -> ()) {
    let url = NSURL(string:string)
    let request = NSURLRequest(URL: url)
    var received:NSMutableData! = nil
    let conn = NSURLConnection(request: request, delegate: GreenUrlConnectionDataDelegate(
            didFinishLoading:{
                completion(data:received, error:nil)
            },
            didReceiveResponse:{
                if let capacity = $0?.expectedContentLength {
                    if capacity > 0 {
                        received = NSMutableData(capacity: Int(capacity))
                    }
                    else {
                        received = NSMutableData()
                    }
                }
            },
            didReceiveData:{
                if $0 != nil {
                    received.appendData($0)
                }
            },
            didFailWithError:{
                completion(data:nil, error:$0)
            }
        )
    )
}

在操场上测试它的代码:

downloadUrl("http://www.google.com") {
    (data:NSData?, error:NSError?) -> () in
    println("completion")
    println("data.size: \(data?.length)")
    println("error: \(error?.localizedDescription)")
}

XCPSetExecutionShouldContinueIndefinitely()

你可以想象甚至可以将胶水类嵌入到需要代表的班级的扩展中,尽管我还没有尝试过。

答案 1 :(得分:0)

闭包与匿名类不同,所以不,我认为你不会找到一个能达到你想要的模式。您使用与JavaScript或C#类似的样式来创建对象实例。这不是Swift。

已经有了在不创建类实例的情况下实现委托的技术。例如,参见ReactiveCocoa'delegate pattern'。