Внедрить делегата с закрытием в 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
     }
});

Ответ 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:()->(),
        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:{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()

Вы могли бы даже встроить класс клея в расширение класса, требующего делегата, хотя я этого еще не пробовал.

Ответ 2

Закрытие - это не то же самое, что анонимные классы, поэтому нет, я не думаю, что вы найдете шаблон, который достигнет того, что вы пожелаете. Вы используете фигурные скобки в аналогичном стиле для JavaScript или С# для создания экземпляра объекта. Это недействительно Swift.

Уже существуют методы для реализации делегатов без создания экземпляра класса. См. Например, ReactiveCocoa шаблон делегата.