mcmatan / TopicEventBus

Publish–subscribe design pattern implementation framework, with an ability to publish events by topic.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Thread-safe

phpmaple opened this issue · comments

Can I run it in background thread or Main?

@phpmaple Great question! TopicEventBus does not deal with threading (As any other EvnetBus or NotificationCenter)
In actual fact, in my personal current project, I have two wrappers over it, one for main an one for background thread (2 different instances) to force to stay thread safe.

Would you like this functionality to be as part of TopicEventBus? What kind of API should you be looking for?

 SwiftEventBus.onBackgroundThread(self, name: "doStuffOnBackground") { notification in
     println("doing stuff in background thread")
     SwiftEventBus.postToMainThread("updateText")
 }

 SwiftEventBus.onMainThread(self, name: "updateText") { notification in
     self.textField.text = "\(self.count)"
 }

like this? https://github.com/cesarferreira/SwiftEventBus

@phpmaple Thanks for the reference.
I dove it to @SwiftEventBus code, and it does not seem to be thread-safe.

If you take a look at "on" method (This is where subscription happens)

` open class func on(_ target: AnyObject, name: String, sender: Any? = nil, queue: OperationQueue?, handler: @escaping ((Notification?) -> Void)) -> NSObjectProtocol {
let id = UInt(bitPattern: ObjectIdentifier(target))
let observer = NotificationCenter.default.addObserver(forName: NSNotification.Name(rawValue: name), object: sender, queue: queue, using: handler)
let namedObserver = NamedObserver(observer: observer, name: name)

    Static.queue.sync {
        if let namedObservers = Static.instance.cache[id] {
            Static.instance.cache[id] = namedObservers + [namedObserver]
        } else {
            Static.instance.cache[id] = [namedObserver]
        }
    }

    return observer
}`

https://github.com/cesarferreira/SwiftEventBus/blob/master/SwiftEventBus/SwiftEventBus.swift

You will notice, that in case you don't use "postOnThread", and just call "post" (as the best practice in example README) the tread will be the one you are posting if from. And same goes for accessing "Static.intance.cache[id]" when subscribing and posting from a different thread, you will probably get an exception.

With that said, I've searched for the topic, and found this library: https://github.com/100mango/SwiftNotificationCenter
And it really is thread-safe, it will force switch thread every subscribe or post for you.

` static func safeSet(key: String, object: AnyObject) {
notificationQueue.async(flags: .barrier) {
if var set = observersDic[key] as? WeakObjectSet {
set.add(object)
observersDic[key] = set
}else{
observersDic[key] = WeakObjectSet(object)
}
}
}

static func safeRemove(key: String, object: AnyObject) {
    notificationQueue.async(flags: .barrier) {
        if var set = observersDic[key] as? WeakObjectSet<AnyObject> {
            set.remove(object)
            observersDic[key] = set
        }
    }
}

static func safeGetObjectSet(key: String) -> WeakObjectSet<AnyObject>? {
    var objectSet: WeakObjectSet<AnyObject>?
    notificationQueue.sync {
        objectSet = observersDic[key] as? WeakObjectSet<AnyObject>
    }
    return objectSet
}`

But there are downsides to this approach too because contexts switching is expensive.
So, my personal opinion is there should be 2 TopicEventBus instances, one for the main thread, and one for background thread. Distributing events across thread is a risky thing, and the programmer must be aware of it by using the correct EventBus, on the correct thread (:

Woh, awesome!!!
Thanks for your explain!

😇 with pleasure