Swift:委托/事件来自 C# 背景

Swift: Delegates / Events coming from C# background

我有一个业务逻辑 class,在进行简单的 Web 服务调用后 returns 一个对象。点击按钮时调用它(在我的视图控制器中)。对我的业务逻辑 class 的调用可能需要几秒钟才能运行,我不想阻塞主线程。

如何在我的 ViewController 可以订阅的业务逻辑 class 中引发事件,以便我知道是时候处理和显示该对象了?

对于这种特殊情况,您可能需要关闭:

class BusinessClass {
    func someExpensiveOperationWithCompletion(completion: (someArg: AnyObject) -> ()) {
        // Do expensive stuff in background
        completion(someArg: "Pass back info here")
    }
}

然后,这样称呼它:

let business = BusinessClass()
business.someExpensiveOperationWithCompletion { (someArg) -> () in
    println("Finished w/ \(someArg)")
}

不同的平台做事不同。如果你在想

How do I raise an event in my BL class that my ViewController can subscribe to ... ?

您将与框架作斗争,并且会遇到困难和过于复杂的代码。

相反,您应该问的更多是

How do I know when an asynchronous operation has completed?

对于 Cocoa,该问题的答案是您可以使用在操作完成时调用的完成 block/closure,或者使用调用方法的委托回调操作完成后在委托上。 (还有更多选择,但这是最常见的两个)。

可以在 this objc.io article

中找到有关何时使用不同通信机制的有用读物

闭包

Cocoa 中的常见设计是将闭包作为异步操作的最后一个参数,在操作完成时调用闭包并将数据作为参数传递到闭包中。如果操作失败,通常还有第二个参数用于可选错误(并使成功数据也可选)

例如下面的例子(为了清楚起见,我为闭包定义了一个类型别名):

typealias FooCompletion = (data: FooData?, error: NSError?) -> ()

func doSomething(completion: FooCompletion) {
    // do asyncrounous work
    let successful: Bool = // based on the operation's success

    if successful {
        completion(data: someValidData, error: nil)
    } else {
        let error = NSError() // fill with information about the error
        completion(data: nil, error: error)
    }
}

你可以使用这样的方法,像这样(这里有一个尾随闭包):

yourBusinessLogic.doSomething { data, error in // FooData?, NSError?
    if let validData = data {
        // it completed (and validData now holds the data from the operation)
    } else {
        // there was an error that should be handled
    }
}

代表

另一种替代方法,即多年来在 Cocoa 中采用的方法,是定义一个委托协议,并为 class 中的可选委托提供一个 属性 来执行异步任务。如果操作既可以成功也可以失败,这两种情况都有委托方法是很常见的:

protocol BusinessLogicDelegate {
    func somethingDidFinish(data: FooData)
    func somethingDidFail(error: NSError)
}

class BusinessLogic {
    var delegate: BusinessLogicDelegate? // optional delegate
    // ...
}

然后在完成可选任务时,将其中一个回调发送给委托(如果有的话)

func doSomething() {
    // do asyncrounous work
    let successful: Bool = // based on the operation's success

    if successful {
        delegate?.somethingDidFinish(someValidData)
    } else {
        let error = NSError() // fill with information about the error
        delegate?.somethingDidFail(error)
    }
}

在这种情况下,您可以将委托分配给业务逻辑实例,调用异步方法并等待回调之一:

yourBusinessLogic.delegate = yourDelegate // doesn't have to be set every time
yourBusinessLogic.doSomething()

// later on, one of the callbacks is called on the delegate