NEW: Learn to build the incredible iOS 15 Weather app today! >>

Key points

There are three pieces of code I’d like to review, just to make sure you understand them fully.

The first thing I’d like to recap is NotificationCenter, which is a system-wide broadcasting framework that lets you send and receive messages. These messages come in two forms: messages that come from iOS, and messages you send yourself. Regardless of whether the messages come from, NotificationCenter is a good example of loose coupling – you don’t care who subscribes to receive your messages, or indeed if anyone at all does; you’re just responsible for posting them.

In project 19 we used NotificationCenter so that iOS notified us when the keyboard was shown or hidden. This meant registering for the Notification.Name.UIKeyboardWillChangeFrame and Notification.Name.UIKeyboardWillHide: we told iOS we want to be notified when those events occurred, and asked it to execute our adjustForKeyboard() method. Here’s the code we used:

let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self, selector: #selector(adjustForKeyboard), name: Notification.Name.UIKeyboardWillHide, object: nil)

There are lots of these events – just try typing Notification.Name. and letting autocomplete show you what’s available. For example, in project 28 we use the Notification.Name.UIApplicationWillResignActive event to detect when the app moves to the background.

Like I said, it’s also possible to send your own notifications using NotificationCenter. Their names are just strings, and only your application ever sees them, so you can go ahead and make as many as you like. For example, to post a “UserLoggedIn” notification, you would write this:

let notificationCenter = NotificationCenter.default Notification.Name("UserLoggedIn"), object: nil)

If no other part of your app has subscribed to receive that notification, nothing will happen. But you can make any other objects subscribe to that notification – it could be one thing, or ten things, it doesn’t matter. This is the essence of loose coupling: you’re transmitting the event to everyone, with no direct knowledge of who your receivers are.

The second piece of code I’d like to review is this, taken from project 21:

let center = UNUserNotificationCenter.current()

center.requestAuthorization(options: [.alert, .badge, .sound]) { (granted, error) in
    if granted {
    } else {

In that code, everything from { (granted, error) in to the end is a closure: that code won’t get run straight away. Instead, it gets passed as the second parameter to the requestAuthorization() method, which stores the code. This is important – in fact essential – to the working of this code, because iOS needs to ask the user for permission to show notifications.

iPhones can do literally billions of things every second, so in the time it takes for the “Do you want to allow notifications” message to appear, then for the user to read it, consider it, then make a choice, the iPhone CPU has done countless other things.

It would be a pretty poor experience if your app had to pause completely while the user was thinking, which is why closures are used: you tell iOS what to do when the user has made a decision, but that code only gets called when that decision is finally made. As soon as you call requestAuthorization(), execution continues immediately on the very next line after it – iOS doesn’t stop while the user thinks. Instead, you sent the closure – the code to run – to the notification center, and that’s what will get called when the user makes a choice.

Finally, let’s take another look at for case let syntax. Its job is to perform some sort of filtering on our data based on the result of a check, which means inside the Swift loop the compiler has more information about the data it’s working with.

For example, if we wanted to loop over all the subviews of a UIView, we’d write this:

for subview in view.subviews {
    print("Found a subview with the tag: \(subview.tag)")

All views have a tag, which is an identifying number we can use to distinguish between views in some specific circumstances.

However, what if wanted to find all the labels in our subviews and print out their text? We can’t print out the text above, because a regular UIView doesn’t have a text property, so we’d probably write something like this:

for subview in view.subviews {
    guard let label = subview as? UILabel else { continue }
    print("Found a label with the text: \(label.text)")

That certainly works, but this is a case where for case let can do the same job in less code:

for case let label as UILabel in view.subviews {
    print("Found a label with text \(label.text)")

for case let can also do the job of checking optionals for a value. If it finds a value inside it will unwrap it and provide that inside the loop; if there is no value that element will be skipped.

The syntax for this is a little curious, but I think you’ll appreciate its simplicity:

let names = ["Bill", nil, "Ted", nil]

for case let name? in names {

In that code the names array will be inferred as [String?] because elements are either strings or nil. Using for case let there will skip the two nil values, and unwrap and print the two strings.

Hacking with Swift is sponsored by Sentry

SPONSORED With Sentry’s error and performance monitoring for iOS, you see mobile vitals that actually matter, can solve any latency issues quickly, and learn how each release is performing over time.

Learn More

Sponsor Hacking with Swift and reach the world's largest Swift community!

Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.7/5

Unknown user

You are not logged in

Log in or create account

Link copied to your pasteboard.