【问题标题】:Implement Delegate with Closure in Swift?在 Swift 中使用闭包实现委托?
【发布时间】:2014-06-11 21:51:59
【问题描述】:

假设我正在使用 Swift 并在框架中调用一个需要委托的方法。

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

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

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

【问题讨论】:

标签: delegates closures swift


【解决方案1】:

您不能定义匿名类,但可以定义一个工作方式非常相似的本地类。我实际上已经从内联类方法迁移了出来,因为 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:@escaping ()->(),
        didReceiveResponse:@escaping ((NSURLResponse!)->())? = nil,
        didReceiveData:@escaping ((NSData!)->())? = nil,
        didFailWithError:@escaping ((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:{response in
                if let capacity = response?.expectedContentLength {
                    if capacity > 0 {
                        received = NSMutableData(capacity: Int(capacity))
                    }
                    else {
                        received = NSMutableData()
                    }
                }
            },
            didReceiveData:{data in
                if data != nil {
                    received.appendData(data)
                }
            },
            didFailWithError:{error in
                completion(data:nil, error:error)
            }
        )
    )
}

以及在操场上对其进行测试的代码:

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

XCPSetExecutionShouldContinueIndefinitely()

您甚至可以将粘合类嵌入到需要委托的类的扩展中,尽管我还没有尝试过。

【讨论】:

  • 你有没有试过这个?我刚刚使用这种模式实现了一个 UITabBarDelegate 并且一切都编译得很好,但是只要选择了一个选项卡,应用程序就会崩溃。一旦我回到对委托使用“self”,一切都照常工作,但是当你在一个屏幕上实现大量回调时,它会变得非常混乱。感谢您的帮助!
  • 我没有将它与嵌入在函数中的类一起使用,因为 REPL 在它上面崩溃了。我有一个版本,我会在几分钟后上传到这里,它基于一个在操场上运行良好的闭包类。
  • 哇,这看起来很有前途!迫不及待地想明天试试!非常感谢大卫!
  • 哦,这是一个很好的模式。这允许使用委托模式设计架构,同时仍然能够用闭包来替代它。非常好。
【解决方案2】:

闭包与匿名类不同,所以不,我认为您不会找到实现您希望的模式。您使用与 JavaScript 或 C# 风格相似的大括号来创建对象实例。这不是有效的 Swift。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2019-10-07
    • 2017-03-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多