我在Java中看到过一种模式,它允许您以类型安全的方式实现回调列表的子集,与使用回调的类内联:
registerHandlers(new ClassWithNoOpMethods() {
@override
public void onFooEvent(FooEvent event) { ... }
@override
public void onBarEvent(BarEvent event) { ... }
}
一切都很好,类型安全。我想在Swift中做同样的事情,但一些谷歌搜索并没有出现任何(恕我直言)优雅的解决方案。所以我想出了这个:
let registrar = EventSource.getEventRegistrar()
registrar.onFooEvent = { event in doSomethingFoo(event) }
registrar.onBarEvent = { event in doSomethingBar(event) }
...
EventSource.removeEventCallbacks(registrar)
这适用于消费事件 - 它只是我感兴趣的事件的子集,它允许我定义代码内联等等。
然而,当我实际实现这个时,我得到了很多重复的样板,非DRY代码。它冒犯了我,但我无法找到更好的方法来实现上面显示的方案。我想请求StackOverflow上的Swift众神向我展示一种更简洁的方法来实现它。
现在看来是这样的:
public class Phone {
...phone stuff...
public class PhoneEventRegistrar {
let phone : Phone
init(phone : Phone) {
self.phone = phone
}
public typealias OnErrorCallback = (PhoneErrorType, String) -> Void
private var onErrorValue : OnErrorCallback?
public var onError : OnErrorCallback {
get { return onErrorValue != nil ? onErrorValue! : {_,_ in} }
set {
assert(onErrorValue == nil, "onError cannot be set twice")
onErrorValue = newValue
}
}
func invokeErrorCallback(type : PhoneErrorType, message : String) {
if let onErrorValue = onErrorValue {
onErrorValue(type, message)
}
}
public typealias OnCallStateChangeCallback = (CallState) -> Void
private var onCallStateChangeValue : OnCallStateChangeCallback?
public var onCallStateChange : OnCallStateChangeCallback {
get { return onCallStateChangeValue != nil ? onCallStateChangeValue! : {_ in} }
set {
assert(onCallStateChangeValue == nil, "onCallStateChange cannot be set twice")
onCallStateChangeValue = newValue
}
}
func invokeCallStateChangeCallback(state : CallState) {
if let onCallStateChangeValue = onCallStateChangeValue {
onCallStateChangeValue(state)
}
}
// and the mostly-similar code shown twice above is repeated for
// each possible callback
}
func invokeErrorCallbacks(type : PhoneErrorType, message : String) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
registrars.forEach({$0.invokeErrorCallback(type, message: message)})
}
func invokeCallStateChangeCallbacks(state : CallState) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
registrars.forEach({$0.invokeCallStateChangeCallback(state)})
}
// again, the mostly similar block of code shown twice above is
// repeated for each possible callback
private var registrars : [PhoneEventRegistrar] = []
public func getPhoneEventRegistrar() -> PhoneEventRegistrar {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
let registrar = PhoneEventRegistrar(phone: self)
registrars.append(registrar)
return registrar
}
public func removeRegistrarCallbacks(registrar : PhoneEventRegistrar) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
assert(registrars.contains({$0 === registrar}), "cannot remove callbacks, no matching PhoneEventRegistrar found")
registrars = registrars.filter({$0 !== registrar})
}
}
如果人们看到对于活动消费者具有相同可用性优势的替代实施方式,我也很乐意看到这些。以下是我曾经想过或尝试过的其他一些选择:
答案 0 :(得分:2)
您的问题有多种解决方案。一种可能是简单地使用NSNotificationCenter
而不是实现自己的事件机制。
使用NSNotificationCenter
,您可以注册活动:
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: #selector(MyClass.myMethod),
name: "com.mycompany.myEvent1",
object: userData)
从任何地方发送事件:
let userData: [NSObject: AnyObject] = [anyObject: anyDataToSend]
NSNotificationCenter.defaultCenter.postNotificationName("com.mycompany.myEvent1", object: userData)
你会在SO和Google上找到很多关于NSNotificationCenter的教程。
另一种方法是使用委托模式。创建协议并将其标记为@objc
,这样协议方法可以标记为“可选”。
@objc protocol MyEventProtocol: class {
optional func foo() -> Bool
func bar()
}
现在每个符合此协议的对象都必须实现bar(),但可以实现foo()。
class MyEventReceiver: MyEventProtocol {
func bar() { // do something }
}
然后您的事件发件人类可以执行以下操作:
class MyEventSender {
weak var delegate: MyEventProtocol? // the name "delegate" is just convention, you can use any other name
init(receiver: MyEventReceiver) {
self.delegate = receiver
}
func sendEventToReceiver() {
if let delegate = self.delegate {
delegate.func() // guaranteed by the protocol
delegate.foo?() // foo is marked as optional, so you have to check it with ?. If foo is implemented on the receiver it will be called, otherwise not.
}
}
}
这是基本原则。通过这种方式,您可以为所有可能的事件定义一个协议,但协议的实现者只需要实现未标记为optional
的方法。他们是“必需的”。
第三种方法是使用默认方法创建协议扩展。
protocol MyEventProtocol: {
func bar()
}
extension MyEventProtocol {
func foo() -> Bool {
return true
}
}
然后MyEventProtocol的实现者不必实现foo(),因为已经有了实现。 (这是一种带有可选方法的“伪造”@objc
协议)如果您为此解决方案添加一些通用机制,您还可以防止重复代码重复。 (协议中的泛型是在Swift 2.2中使用associatedtype
完成的,请参阅其他教程)