iOS Design Patterns - Part 5: Multicast Closure | Ray Wenderlich

Learn about the multicast closure delegate pattern, a spin-off pattern from delegate, which will prepare you for auto re-login authentication (next video).


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/3816-ios-design-patterns/lessons/5

Hi, Joshua! Thanks for great series, can’t wait for next videos.

I’ve got a question, what’s the main benefit of using such pattern over using plain NotificationCenter? It also allows you to establish one-to-many relationship between objects and a lot easier (or at least familiar for most developers). And it’s a bit vague from playground why we need delegate object at the first place?

I mean lines:

let delegate = NSObject()

multicastDelegate.addClosurePair(for: delegate, success: { 
    print("Success")
}, failure: {
    print("Failure")
})

So is this delegate (aka objectKey) just to put callback to mapTable?

Could you please, clarify a bit or maybe next video is the answer. Sorry, for maybe a vague questions.

1 Like

There are a lot of benefits actually!

  1. The MulticastClosureDelegate implementation shown here is thread safe… well, once you complete the challenge it is… NotificationCenter is not.

  2. Since it also uses a map table, you don’t have to worry about “unregistering” anything… you do have to remember to unregister notification center observers, or you’ll crash your app.

  3. Notification center is a “shotgun” approach to sending a notification… do you want to invite someone some (aka a delegate) or a group (aka multicast delegate) of people for dinner? While you could invite everyone in the town by advertising on the radio, you probably shouldn’t? That is, what if that one guy comes… you know, mr. crashes-your-app every-day?

Seriously, though, it doesn’t always make sense to send a broadcast notification, when you just want to send a targeted message.

  1. This implementation also adds the option to “notify once” and remove observers. This is actually really useful, as you’ll see in the next video.

With all of the above, you may be tempted to say, “Well, I’ll just always use MulticastClosureDelegate, then!”

I wouldn’t go this far… there’s definitely still use cases for Notification Center too.

After all, both of these are simply tools, so use them appropriately. ;]

Check out the next video, where you’ll get more experience seeing just how useful this particular pattern and implementation thereof can be.

Yes, these delegate objects are mainly used to keep the callback alive.

Multicast Closure “Delegate” is a play on words, if you will…

That is, the delegates are simply keys passed to the map table.

Why do I even call them “delegates”?

Inside the closures, these objects are likely doing real work… see the next video for an example…

So, in a way, they are exactly like delegates:

  • A delegating/sender object posts a message
  • Each of the delegates on MulticastClosureDelegate receives the message
  • Each delegate does something in response to receiving the message.

Also, this particular implementation was somewhat adapted/inspired by this library:

There, these are truly “delegate” objects. This is useful too, but only if you want to define a protocol to talk over.

I usually use this for long-lived multicast delegate relationships. Whereas, I use the multicast closure delegate most often with short-lived objects.

There’s no reason why you couldn’t use multicast closure delegate long term, however, if you wanted to do it. :]

In that case, it’d likely make more sense to change some of the default parameter values, so the closures won’t automatically get removed (as they do now) by default.

Hi Joshua,
Thanks for this awesome series.
I’ve got a question: I found no matter how I executed the requestAuthToken() from UserViewController or from NetworkClient, the MulticastClosureDelegate’s callbacks count is always 1. I am wondering in what kind of circumstance, the callback count will more than 1. Please explain this more explicitly. Thanks a lot.

Hello, again!

Can I afford myself another question? Am I getting right that on diagram on the slide Multicast Delegate at 0:52 described classic Observer pattern? One-to-many, through a protocol, etc. Just to be on the same tune.

Thanks!

Hi @jrg.developer Joshua!

Thanks a lot for the video series!

Have a question about mapTable property.
It’s var mapTable = NSMapTable<AnyObject, NSMutableArray>.weakToStrongObjects()
But why we can’t use
var mapTable = NSMapTable<AnyObject, Callback>.weakToStrongObjects()
where Callback will be successor from NSObject? because you told it should be an object.

I’m not that strong in this pattern - i’ve seen it for the first time in this tutorial :slight_smile:

Thanks for the reply. :wink:

If you do this, you’d only be able to register one closure per object key.

By using an NSMutableArray, you can register multiple closures per object key.

There isn’t really a “right” choice here: it just depends on your project’s needs.

Personally, I tend to lean towards greater flexibility, and hence, I went the NSMutableArray route.

Regarding AnyObject requirement for objects and keys, this is a restriction that's imposed byNSMapTable`., which unfortunately is inherited from Cocoa and Objective-C and doesn’t currently have a Swift version provided by Apple… I wish there was one! I’ve considered writing my own, but the work to do so is non-trivial. ;]

If you run across a good Swift implementation of NSMapTable, definitely post and let us know! :]

I was actually talking about a multicast delegate implementation like this one:

Multicast Delegate is very popular in other languages, such as C#.

Recently, I’ve noticed it’s starting to become more commonly used in Swift too. :]

I wanted to show a different, spin-off approach to this, and hence, I showed Multicast Closure Delegate in this video.

Fundamentally, however, they’re basically the same: both seek to dispatch a message to many observers.

It just so happens Multicast Delegate requires objects to implement a “delegate” protocol, and MulticastClosureDelegate uses closures instead to get around this requirement.

Both are extremely useful, and I have even used both in the same project before. :]

For example, if multiple network requests were made that needed auth token.

In the example app, this actually doesn’t occur… it’s possible in some theoretical future this could be needed in the demo app, but more realistically, your own apps likely will have this issue. That is, if you’re doing anything other than very simple networking.

In my own apps, I usually encounter this problem after writing a few networking calls, especially ones that need to happen periodically in the background.

Hah) Thanks a lot)
Now it’s clear :slight_smile:

Video isn’t working on either safari or chrome. Videos 5 through 10 aren’t working and I have to prepare for interviews. Please fix this asap.

Hi @angad23dec

Sorry for the problems you’ve been experiencing with this course. This was due to a CDN issue with our provider. They’re working on a fix for it, which should be deployed by the end of the week.

In the meantime, I’ve just deployed a version of the site that should allow you to view videos again. It uses a fallback video player, which doesn’t have quite the same functionality that you’re used to, but it will at least allow you to watch videos again.

Once again, apologies for the the problems

Sam

Hi @jrg.developer Joshua
congratulations to the course, I find it really useful.
For the first time I tried to use the class NSMapTable with this fifth lesson
and I would have a few questions about it, which I did at the following link

did you find the same problem as well?
is a normal behavior for NSMapTable?

I’m glad you liked the course. :]

Regarding your question, NSMapTable's weak behavior options work best when you don’t care when keys/values are released, but rather, you do care that the keys/values aren’t strongly retained and will be released at some point after the object of interest becomes nil.

Why so?

As a Foundation class, the authors of NSMapTable had to worry about and balance both features and performance.

Consequently, as an optimization for performance, weakly referenced objects that become nil are NOT immediately removed from the map table…! Rather, this happens “later” for it can be efficiently done – such as when the map table internally gets resized, etc.

See this writeup for an experiment done on NSMapTable's behavior for more details:

http://cocoamine.net/blog/2013/12/13/nsmaptable-and-zeroing-weak-references/

Thank you for the reply !!!

The example in this video is far too much too soon.

Why we don’t just use the Observation pattern ? what is the benefits of using the Multicast Closure over creating a simple Observable class Like this

class Observer<Value> {
    typealias ObserverBlock  = (Value) -> Void

    weak var observer: AnyObject?
    let block: ObserverBlock

    init(observer: AnyObject, block: @escaping ObserverBlock) {
        self.observer = observer
        self.block = block
    }
}

public class Observable<Value> {

    //MARK: - Private properties
    private var observers  = [Observer<Value>]()

    //MARK: - Public properties
    public var value : Value {
        didSet {
            self.notifyObservers()
        }
    }

    //MARK: - Struct lifecycle
    public init(_ value: Value) {
        self.value = value
    }

    //MARK: - Observation
    func observe(on observer: AnyObject, observerBlock: @escaping Observer<Value>.ObserverBlock) {
        self.observers.append(Observer(observer: observer, block: observerBlock))
        observerBlock(value)
    }

    func remove(observer: AnyObject) {
        self.observers = self.observers.filter({ $0.observer !== observer })
    }

    //MARK: - Helpers
    private func notifyObservers() {
        for observer in self.observers {
            observer.block(value)
        }
    }
}

@aladin You had an excellent question, and I wanted to answer it as I’m sure others have it too. I see you’ve deleted it for some reason, though.

Basically, his question was:

Why not use the Observer pattern instead of this one?

For example, you can create an Observable wrapper class [or use KVO].

(Wherein I added “or use KVO” as another viable, similar alternative.)

In truth, I use BOTH the Multicast Closure Delegate pattern and the Observer pattern. :wink:

The Observer pattern is useful when you want an object to observe changes made to another object. Usually, this means changes made to another object’s property values.

The Multicast Closure Delegate pattern is useful when you want to notify several delegates about an event that has occurred.

Is there overlap? Definitely!

However, the difference is intent :

  • Multicast Closure Delegate isn’t limited to just property changes, but rather, it’s event driven. For example, “when an admin user logins in with given permissions, do whatever” is very possible using Multicast Closure Delegate.

  • Observer is usually (but not necessarily “always”) for property changes. For example, “when a user changes his name, update a label on screen” is very possible using Observer.

Which is the better pattern? Neither! They are solving similar but ultimately different problems.

It’s okay to mix and match design patterns in the same project - just make sure it makes sense for whatever your ultimate goal is!

:]

THanks,very useful video…but I need some more experience to understand it fully…lol