Tuesday, July 26, 2016

Thoughts on making TinyPubSub a little less tiny

Thoughts on making TinyPubSub a little less tiny

TinyPubSub is a very simple Publish/Subscribe library created mainly for passing events between views in an Xamarin Forms application that uses MVVM. You can read about it at https://github.com/johankson/tinypubsub.
What I'm thinking about doing is extending it with two features
  • Passing of data
  • A stack based recipient model

Passing of data

TinyPubSub only allows for publishing events from one source to many recipients. It was originally create for notifying other views to reload or refresh their data. At first this was pretty much all it was intended to do. But now I can't help myself and I would really like to publish data as well.
This is the original way to subscribe and publish an event.
In the first view model
TinyPubSub.Subscribe("ducks-loaded", 
   () => { RebindGui(); });
In another view model
TinyPubSub.Publish("ducks-loaded");
Let's say I want to pass data, it could look like this
TinyPubSub.Subscribe("duck-color-updated", 
   (c) => { RecolorDuck( c ) } );
And in the publish part
TinyPubSub.Publish("duck-color-updated", c);

An example

Let's say you're buildning an app for configuring a car. The first page is to choose the model. On this page there is a button to choose your color. The original page simply registers for the color-chosen event and waits happily for that to happen. We then create a generic choose color page that knows nothing about what page that really needs that color. When the color finally is choosen the page fires a color-chosen event and the first page will receive it.
All is fine until you get another subpage that also wants a color choosen. You can solve that in a number of ways. The first being to register different events for different colors choosers and pass an argument to when we create the color picker page. This is messy and could easily get out of hand.
My proposed solution is to create a function where you can state that only the latest registered listener will handle the event.

A stack based recipient model

Enter the stack based recipient model.
The mechanism behind this is simple. The latest registered recipients of a specific event is the only one that will receive an event.
Since all events for a page is deregistered automatically in TinyPubSub it will be simple to reuse the color-picker page multiple times.
To revisit the car example, just before clicking the button for coloring your car door you register to the color-chosen event with the `SubscribeExclusive(...) method.
TinyPubSub.SubscribeExclusive("color-chosen", 
   (c) => { RecolorCarDoor( c ) } );
await Navigation.PushAsync(Resolver.Resolve());
Then it doesn't matter if you have another page listening for the color-chosen event. Only the page before will get the event. And when the page goes out of scope, the subscription for the event will be removed and the page before will get the event instead.
This also means that the ColorPickerPage could check at runtime to see if there are any recipients at all and throw an Exception if there is none.

Summary

This is still not implemented. I thought I just write it down first and get some comments on it.

4 comments:

  1. I like the syntax for passing of data. I assume the methods will be generic so the value passed will be strongly typed and you won't have to cast from object? Are you going to have overrides for multiple arguments or leave it at just one?

    I currently use the MessagingCenter class to send data. Instead of passing this to the first parameter, I new up a messaging object that gets passed to the subscriber.

    MessagingCenter.Send(new NetworkError(Resources.NetworkNoConnection), NetworkError.Message);


    MessagingCenter.Subscribe(this, NetworkError.Message, m => OnNetworkError(m));

    The Message parameter is just a const string so I don't have to correctly type the message key every time. This works, but it is a bit heavy and requires that I create a messaging object for each type of message I want to pass. Your approach is a lot lighter.

    ReplyDelete
    Replies
    1. The methods will be generic and perhaps async as well. I was originally thinking about one argument but why not multiple? Good point!

      I also used to use MessagingCenter but it just got so bloated after a while. For my needs, TinyPubSub fits the bill. But I'm really not sure if I should bloat it or not. :)

      Delete
  2. Apple's flagship operating system iOS 11 is nearing it's release. There will be quite a few changes from iOS 10 as well as some compatibility updates. You can check out my site to get all the details about iOS 11, the compatible devices
    iOS 11 beta

    ReplyDelete