NotificationCenter, delegate, closure or KVO: how do you choose?

2.4.4 · L3 · Interview

Predict first

Which fits “tell several unrelated screens that the user logged out”?

// A: NotificationCenter
// B: a delegate
// C: a completion closure
  • A
  • B
  • C

Mental model. A delegate is a phone call, a closure is a postcard reply, and a notification is a town crier.

Ask how many listeners and how much do they need to know each other. NotificationCenter is one-to-many with no knowledge of who listens: good for app-wide facts (user logged out, locale changed) and system events. A delegate is one-to-one with a typed contract and lets the receiver shape behaviour (“should I allow this?”). A closure suits a one-off result such as a completion. KVO watches one property on one object.

The price of notifications is invisibility: nothing in the type system says who reacts, so flows become hard to trace and test. Use them for broadcast facts, not for control flow you could express with a direct call.

It is a broadcast fact with many unknown listeners, which is what the notification center is for.

NotificationCenterDelegateClosureKVO
Receiversmanyoneonemany
Couplinga name stringa protocola closure typea key path
Typed payloadnoyesyesyes
Best forapp-wide broadcastscustomising behaviourone-off resultswatching one property

Common traps

  • Using notifications as a service locator. Posting to call a specific object is a delegate in disguise.
  • Several observers of one event with shared state. Order is undefined, so they must not depend on each other.

They might follow up with

  • What replaces these in new code? AsyncStream and Combine publishers for streams, and Observation for UI state.
  • How do you test code that posts notifications? Inject a private NotificationCenter() instead of using .default.

Related questions

  • 2.4.1 How does NotificationCenter deliver a notification, and on which thread?
  • 2.4.5 How does KVO work in Swift, and why does it sometimes never fire?

← How do you pass data in a notification safely?   How does KVO work in Swift, and why does it sometimes never fire? →