【发布时间】:2017-01-03 10:56:40
【问题描述】:
我正在从 Java\C# 背景进入 Swift,但无法弄清楚一件事。
有什么方法可以在 Swift 对象中创建类似于 C# 中的事件 (Action<T>) 的通知事件?
或者我是否应该为此目的使用闭包?
【问题讨论】:
我正在从 Java\C# 背景进入 Swift,但无法弄清楚一件事。
有什么方法可以在 Swift 对象中创建类似于 C# 中的事件 (Action<T>) 的通知事件?
或者我是否应该为此目的使用闭包?
【问题讨论】:
您可以使用委托和协议来做到这一点。这是一个简单的示例,假设您有一个带有 2 个 ViewController 的 Storyboard,分别称为 ViewController 和 SecondViewController(故事板 ID 为“Main”)。
protocol SampleProtocol: class {
func didLoad()
func didAppear()
}
class ViewController: UIViewController, SampleProtocol {
override func viewDidLoad() {
super.viewDidLoad()
let secondViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "SecondVC") as! SecondViewController
secondViewController.configure(delegate: self)
addChildViewController(secondViewController)
view.addSubview(secondViewController.view)
}
func didLoad() {
print ("didLoad")
}
func didAppear() {
print ("didAppear")
}
}
class SecondViewController: UIViewController {
weak var delegate: SampleProtocol?
override func viewDidLoad() {
super.viewDidLoad()
delegate?.didLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
delegate?.didAppear()
}
func configure(delegate: SampleProtocol) {
self.delegate = delegate
}
}
【讨论】:
据我了解,C# 中的 Action<T> 委托只是一个 Void-returning 函数委托,它封装了一个可以通过委托执行的方法。
由于 Swift 支持高阶函数,您可以定义自己的 Action<T> 类型,其唯一目的是为类型保持器类型 T 的单个参数封装 Void-returning 方法。
struct Action<T> {
private let f: (T) -> ()
init(_ f: @escaping (T) -> ()) {
self.f = f
}
func run(_ val: T) {
f(val)
}
}
我们可以使用这个,例如封装一个函数:
func addOneAndPrint(val: Int) {
print(val+1)
}
let increaseAndPrintAction = Action(addOneAndPrint) // inferred to Action<Int>
increaseAndPrintAction.run(1) //2
或提供的闭包(类似于在 C# 中向 Action<T> 提供 lambda):
let increaseAndPrintAction = Action { print($0 + 1) }
increaseAndPrintAction.run(1) // 2
[1, 3, 5].forEach(increaseAndPrintAction.run) // 2 4 6
现在,我不知道 C# 中 Action<T> 的常见用例,但如果您想在完成某些任务时使用它来执行某些事件,您可能只想使用提供的完成处理程序关闭要执行的任务:
func increaseTask(_ val: inout Int, completion: (Int) -> ()) {
val += 1
// ...
completion(val)
}
var val = 1
increaseTask(&val) { print("Successfully increased to value \($0)") }
// Successfully increased to value 2
print(val) // 2
【讨论】:
正如其他人所说,swift 中没有 event 关键字。但是很容易实现你的。
我已经完成了满足这些要求的swift package。
source code 非常简单,不到 100 sloc。
这是一个简短的版本:
public class Event<T> {
private var handlers:[EventHandler<T>] = []
private init() {}
private func invoke(sender:AnyObject?,value:T) -> Void {
for handler in self.handlers {
handler.handle(sender,value)
}
}
public static func += ( event: Event, handler: EventHandler<T>) -> Void {
{
event.handlers.append(handler)
}
public static func -= ( event: Event, handler: EventHandler<T>) -> Void {
event.handlers.removeAll{$0 === handler}
}
public static func create() -> (invoke:Delegate<T>,event:Event<T>){
let res = Event<T>()
return (res.invoke,res)
}
}
EventHandler 在哪里
///needed as Swift doesn't allow func ===
public class EventHandler<T> {
private var _handle:Delegate<T>
public var handle:Delegate<T> {
return self._handle
}
public init(handle:@escaping Delegate<T>){
self._handle = handle
}
}
而Delegate 是
public typealias Delegate<T> = (_ sender:AnyObject?,_ args:T) -> Void
使用 asis :
let tmp = Event<String>.create()
var handler = EventHandler<String>(handle: { sender, args in
print(args)
})
tmp.event += handler
tmp.invoke(self,"Hello world !")
//handler should print "Hello world !"
tmp.event -= handler
此解决方案提供与 C# 几乎相同的语法:+=、-=、Invoke,并防止在声明范围之外调用 invoke。
【讨论】: