Swift中的事件概念是否类似于C#中的事件?

时间:2017-01-03 10:56:41

标签: swift swift3

我从Java \ C#背景进入Swift并且无法弄明白一件事。 有没有办法在Swift对象中创建类似于C#中事件(Action<T>)的通知事件?

或者我想为此目的使用闭包?

3 个答案:

答案 0 :(得分:1)

您可以使用委托和协议执行此操作。这是一个简单的例子,假设您有一个带有2个ViewControllers的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
    }
}

答案 1 :(得分:0)

正如我所理解的,C#中的Action<T>委托只是一个Void - 返回函数委托,它封装了一个可以通过委托执行的方法。

由于Swift支持更高阶函数,因此您可以定义自己的Action<T>类型,其唯一目的是为类型所有者类型T的单个参数封装Void - 返回方法。

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

答案 2 :(得分:0)

正如其他人所说,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