Tutorial

Passing Data in iOS: Delegates, Notifications, and Closures


Long time no see dear readers and Appcoda fans! It’s been a long time since my last post here at Appcoda, and I am really glad to be back!

Today, I’m going to discuss about an important and definitely interesting topic which focuses on a quite often overlooked concept. And, this question is commonly asked by beginners:

How do you implement communication internally in apps and exchange messages properly among classes or other entities in Swift projects?

Undoubtedly, it is a must-have knowledge for every developer, new or not. Knowing what the available tools and techniques are, what works best, where and when, is crucial for a proper development process. After all, being able to send messages and data back and forth among classes is not something that one can optionally learn; instead, it’s one of the first things a developer should know about.

So, in this post we are going to see the following methods that allow to perform in-app communication:

  • Delegation pattern
  • Notifications
  • Closures & action handlers

Usually, not all these three concepts are met together in one post, but one can find a lot about each topic separately. I felt the need to write a tutorial that concentrates them all, as they actually serve the same purpose; to let us exchange messages and data among our programming structures and entities. Through simple words and practical programming examples I will try my best to make it easily understandable how each concept works. Hopefully, by the end of the tutorial some valuable lessons will have been taught.

A programming tutorial without a bit of coding doesn’t sound right, so we will work on a demo application that will let us meet each concept as thoroughly as possible given the limits of a single post. For sure, what you will see next are standard techniques which you just have to adjust and use them in your projects. And by having said that, let’s not lose any more time here and let’s move on to the actual interesting stuff! Happy reading!

A Starter Project To… Start With

We are meant to make our hands dirty, but we won’t write a full app from the beginning. We will focus on the important stuff only, as all the rest have been already made in a starter project that you should get from here.

Supposing that you have downloaded the starter project and opened it in Xcode at this point, it’s time for a quick tour. Our main objective today is to build a shopping list app as much featured as possible, so we can apply all principles we will learn about delegates, notifications and closures. By the end of this tutorial, the demo app will be capable of:

  • Creating shopping lists.
  • Keeping and displaying a collection of all shopping lists added to the app.
  • Selecting a shopping list and displaying its items.
  • Editing an existing shopping list.
  • Renaming & deleting shopping lists.
  • Adding, editing, and deleting shopping list items.

If you run the starter project, you won’t see much happening. Yes, you can navigate from one view controller to another, but no data can be saved, nor there is other significant operation you can actually test. And that’s because vital parts regarding communication among app classes is still missing.

It would be more interesting to go through the code though. First of all, you will find three different view controllers:

  • AllListsViewController: This is the place where all shopping lists are gathered and displayed. From this view controller, you can initiate the creation of a new list, editing an existing one, renaming and deleting.
  • ShoppingListViewController: It lays out all items of a list, and allows to create, edit, and delete items.
  • EditItemViewController: Its name suggests what is all about. You create, edit or delete shopping list items.

Additionally, there is a file called ShoppingList.swift which contains two structs:

  1. ShoppingList: It represents a shopping list programmatically and it contains properties for: id, name, edited timestamp & items of a list.
  2. ShoppingListManager: It manages a collection of ShoppingList items and it offers a variety of useful functions. An instance of this struct is used in AllListsViewController view controller. It is called listManager and it’s our tool to handle shopping lists.

You will also find a file named NotificationNameExtension.swift. This file is currently empty, but soon enough that’s going to change. More details later.

Finally, there are custom cells and custom views implementations. What is particularly interesting among them, is the RenameListView, a custom view that allows to rename a shopping list. Well, not yet, but at some point will do. Keep it in mind, as we will work on it when we’ll be discussing about closures and action handlers.

Take your time to familiarize yourself with the starter project. Go through the code, examine the view controllers and other classes or structs, and find out what is offered in the starter project and what not. When you feel ready, keep reading. Delegation pattern comes first!

Delegation Pattern in Simple Words

Consider the following two classes, ClassA and ClassB.

ClassA initializes an object of ClassB, aiming to use services that ClassB has to offer. We know that passing messages from ClassA to ClassB is straightforward, as long as there are public properties or methods to access. For example:

The troubling part is: How do we pass messages from ClassB back to ClassA?

And here’s where delegation pattern gets into play! Let’s go through the steps involved in implementing it.

Step One

The first step required in order to send messages from ClassB back to ClassA is to implement a custom protocol. It will contain functions that are meant to be:

  • Implemented by ClassA so they perform actions specific to that class.
  • Called by ClassB, so ClassB can trigger actions in ClassA or pass data to it through the function parameter values.

As a common convention, such a protocol has the delegate word as a suffix (that’s not mandatory, but recommended for clarity in code). Also, it usually starts with the name of the class it regards.

Step Two

ClassB declares a property which is of the custom protocol’s type:

Once again for convention reasons, delegate property is named like that for making the code comprehensive and easily understandable.

The truth is that it can be named any way you want, such as myDelegate, customDelegate, monday, whatIsThis, whatAFreakingGreatCode, iLoveDelegates and so on – Ok, just don’t do that!

Step Three

ClassA adopts the new custom protocol, and implements its functions:

Step Four

ClassA assigns itself to the delegate property of ClassB. In other words, it’s becoming ClassB‘s delegate.

Step Five

ClassB can use protocol’s functions to communicate with its delegate, which is ClassA. A piece of advice: Always make sure that the delegate property is not nil.

That’s the roadmap to implement the delegation pattern. In the hypothetical example above I mentioned two classes only, but to be honest and more precise, any class that adopts the ClassBDelegate protocol and assigns itself to the delegate property of ClassB can become ClassB‘s delegate, and therefore establish a bi-directional communication.

Delegates in Action

Let’s see how delegation works in action, and let’s jump straight into our demo application. We will apply the steps outlined above in order to make it possible to:

  1. Add a new item created in the EditItemViewController to the items collection of the shoppingList property in the ShoppingListViewController.
  2. Update an edited item in EditItemViewController to the items collection of the shoppingList property in the ShoppingListViewController.
  3. Remove an item from the items collection of the shoppingList property in ShoppingListViewController that had been previously deleted in the EditItemViewController.

We will start by creating a new custom protocol that we’ll name EditItemViewControllerDelegate. And we will do that in the EditItemViewControllerDelegate.swift file.

The first protocol’s function will let EditItemViewController tell ShoppingListViewController that a new item should be added to the items collection:

However, EditItemViewController is unable to access any EditItemViewControllerDelegate functions without having declared a delegate property in it first. So, let’s do that as the next step:

Before we make use of the delegate property, let’s open the ShoppingListViewController.swift file. We will make ShoppingListViewController class adopt the EditItemViewControllerDelegate protocol and subsequently implement its function. In the function’s body we’ll append the given item to the items collection of the shoppingList object, and we’ll refresh the table view so the new item gets displayed.

So, in the ShoppingListViewController.swift file go after the closing of the ShoppingListViewController class. Add the following extension:

With the above addition, we just made it possible to save and display a new shopping list item created in the EditItemViewController. But we’re not okay yet, as we haven’t set ShoppingListViewController class as the delegate of the EditItemViewController. To do so, go to the prepare(for:sender:) method, and append the editItemVC.delegate = self as shown next:

You might be wondering why making self the delegate of the EditItemViewController takes place in the prepare(for:sender:) method. Well, that’s because prepare(for:sender:) is invoked when a segue is triggered, and it’s the place where we make any configuration regarding the view controller that’s about to be presented, before it gets presented.

To make that a bit more clear, EditItemViewController is presented when it is asked to do so in two cases: When adding a new item and when editing one. The following line is the responsible for that in both:

Now, right between the action that makes the above line to be executed and the actual presentation of the EditItemViewController, it’s the prepare(for:sender:) method that can be employed to do custom stuff regarding the upcoming view controller. And so we do.

Note: The best place to set your class as the delegate of another class, is right after the initialization of the latter. In our case and since EditItemViewController is a view controller which gets initialized automatically by the segue, prepare(for:sender:) method is the only place we can consider as the initialization place. We access our view controller then by using the segue.destination property and casting to the appropriate type.

Back to the EditItemViewController.swift file, where we are ready to make the Save button work. To refresh our memory, our goal is to type an item’s name in the textfield, and by tapping on the Save button to send that item to the ShoppingListViewController, so it gets added to the items collection and eventually be displayed to the table view.

Head to the saveItem(_:) IBAction method and update it as follows:

What happens here:

  • At first, we make sure that user has typed something on the textfield, and they are not just trying to save while item’s name is being missing.
  • Next, and that’s important, we make sure that the delegate property is not nil.
  • Then, we call the shouldAdd(item:) function of the EditItemViewControllerDelegate protocol, providing text as the argument that represents the newly added item.
  • Finally, we dismiss the view controller by popping it from the navigation stack and we go back to our shopping list.

That’s it! The delegation pattern has been successfully applied, as the EditItemViewController class can now talk back to the ShoppingListViewController class by letting it know that there is a new item added, and by handing off that item at the same time so it can be further handled.

Feel free to test the app now, and create fake shopping list items. Each and every item you add is getting saved when you tap on the Save button!

t62_1_save_items

But… wait a minute. What if we add twice or more times the same item?

Using Delegate Methods To Collect data

t62_2_same_items

From a user’s point of view, the app shouldn’t add an item if it already exists. It doesn’t make sense to have a shopping list in which we can add milk 15 times, or tomatoes 10 times.

Let’s try to fix that. But the problem is: We have no information at all whether the item exists already or not at the time of saving, such that we can avoid adding it to the shopping list again.

Trying to deal with that by passing the entire items collection from ShoppingListViewController to EditItemViewController is obviously a really bad idea, totally counter-performant and a bad practice. So, what can we do?

In the majority of the times that you will create delegation-related protocols, their functions will not return any value. The one and only delegate function we implemented so far (shouldAdd(item:)) is the best example of the kind of functions you will most probably be creating in such protocols. But, delegate functions can return a value which comes from the class that adopts the protocol and has been set as the delegate class. In other words and regarding our demo specifically, such a delegate function could return data straight from the ShoppingListViewController class.

Aha! Here we are!

Let’s ask ShoppingListViewController if the item we are trying to save already exists or not prior to saving it, and if it doesn’t exist then we allow it to be saved, otherwise we don’t!

Now we know what to do, let’s do it! Back to the EditItemViewControllerDelegate protocol, let’s append the following function:

That function returns a Bool value. When true, the item we’re trying to add exists already so we just don’t keep it. When false, the item doesn’t exist and we can append it to the items collection.

Time to switch back to ShoppingListViewController.swift file, where we need to implement that function. Simply enough, we check for the item existence and we return true or false accordingly:

The information we need can be now given from ShoppingListViewController to EditItemViewController when required. However we still have to update our previous saving code in EditItemViewController so we can actually make use of it.

Let’s pay a second visit to the saveItem(_:) IBAction method in the EditItemViewController.swift file. Our update will make the shouldAdd(item:) delegate function get called if only the isItemPresent(item:) returns false. Otherwise… let’s be polite! We’ll present an alert notifying users that the current item has been added already to the shopping list.

Replace the previous contents of the saveItem(_:) IBAction method with these shown below:

Running the app again will show that this new addition we just made is the solution we have been looking for!

t62_3_item_exists
Note: In that new delegate method we just implemented, we return a Boolean value. However, delegate methods can return any value that is necessary to the app you are making.

More Delegate Functions

Even though we have gone from nothing to something, our demo application would be more meaningful and complete if we support two more features:

  1. Edit and replace an existing item,
  2. Remove an item.

Both of these actions are initiated in EditItemViewController, but they actually regard the ShoppingListViewController class. So, since EditItemViewController has to say something to ShoppingListViewController again, we are in the need of two new delegate functions.

We’ll begin by implementing the edit and replace functionality. What we need to achieve here is to present the EditItemViewController and pass an existing item to it, so users can update it and save it back. Which one? Any item tapped on the table view in the ShoppingListViewController view controller.

For our convenience, the way to select an item and pass it to the EditItemViewController has been implemented in the starter project already. Any selected item in the table view in the ShoppingListViewController is assigned to the editedItem property of the EditItemViewController, so we take it for granted that the editedItem is the one that holds the item that should be edited when tapping on any item in our list.

Focusing again on the delegate functions we want to add, let’s head back to the EditItemViewControllerDelegate protocol, which we extend with the following function:

What that method is supposed to do is shown pretty clearly in its implementation that takes place in the ShoppingListViewController.swift file right next:

If the item is found, then we replace it with the new value and the table view is reloaded, otherwise nothing happens.

We’ll go now to the saveItem(_:) IBAction method in the EditItemViewController for a third time, as we need to update it even further.

We’ll focus on the case where the item we’re trying to save is not present in the items collection, and we’ll check to see if we’re editing an item or not. We can achieve that simply by checking if the editedItem value is nil or not. If it’s not nil and therefore we’re editing an existing item, we’ll call the brand new delegate function we implemented in this part. Otherwise, we’ll save the item as a new one.

Let’s make it possible to delete an item now. For that, we’ll add one last delegate function in the EditItemViewControllerDelegate protocol:

Its implementation in the ShoppingListViewController view controller is more than straightforward. Open the ShoppingListViewController.swift file and update it with the following:

Back to EditItemViewController you’ll find an IBAction method called deleteItem(_:) which is still empty. Time to make it working:

Test the app again. Now it’s totally possible to add, edit and remove items in the shopping list!

t62_4_edit_item

Notifications

Employing iOS SDK’s NotificationCenter class to send notifications is a great way to exchange messages internally in your app. Notifications may contain or not data, and it’s a good way to support communication among various parts of the app that are either directly related or not.

The particularly interesting thing with notifications is that the sender (the creator of the notification) broadcasts a message, and anyone observing for it can get it and perform its own actions. Even though we won’t take advantage of that feature of notifications here (we’ll stick to one-to-one communication, not one-to-many), you should be aware of it in case you need it.

Implementing notifications on an iOS (or any other Swift based) project has a quite particular workflow:

  1. Post the notification. That happens on the sender’s side, and it’s the place where we include any additional data that might be required by the receivers of the notification.
  2. Observe for the notification on any class or struct that required.
  3. Implement a function that defines all the actions that should take place when the notification is received.

Custom names must be given to custom notifications, and naming is quite important, because it makes it easy to distinguish notifications. Keep that in mind, as having multiple custom notifications in large projects can become really confusing, and good naming can save you time from searching around what each notification is for. More about that is coming right next.

Implementing Notifications On The Demo project

Back to our demo project. So far, we are able to add items to a shopping list, however we don’t keep that list into the collection of lists in the AllListsViewController. What we are obviously missing is to make the ShoppingListViewController class capable of saying to AllListsViewController that a new list has been created. Based on what we’ve seen so far, we could use delegation pattern to achieve that, but no! This time we’ll do it with notifications!

For the purpose of this tutorial, we are going to create two custom notifications:

  1. The first will notify AllListsViewController that a new shopping list has been created.
  2. The second will notify AllListsViewController that an existing shopping list has been modified.

The sender of both notifications will be the ShoppingListViewController class, as that’s the one knowing when to post them. AllListsViewController will observe for them, and it will perform certain actions upon receiving them.

Specifying Notification Names

Before we start implementing, let’s focus on the notification names first. A notification name is of Notification.Name type, where Name is a struct in the Notification class (find out more here).

Extending Notification.Name struct with custom notification names is considered as a best practice so they’re widely available all over the project. That way not only is unnecessary to remember them, but it also helps to avoid typographic mistakes. Plus, Xcode will auto-suggest them!

So, this is what we’re about to keep on doing on our demo project. In the starter project, there is a file called NotificationNameExtension.swift. Meanwhile, the is blank. Let’s change that by extending the Notification.Name struct and create our custom notification names:

Both names describe what they are all about. They are declared as static properties, so they become part of the type and we don’t need to create instances of Notification.Name so we can use them.

Reminder: These are not notifications, they are just names we will give to the notifications that we will create next.

Posting a Notification

Now that our custom notification names exist, let’s post our first notification. Head over to the ShoppingListViewController.swift file, and look into the updateParent() method. This method is called every time the back bar button is tapped, so it’s the best place to let AllListsViewController know that we have finished creating or editing a shopping list.

The most obvious way to send a notification is to initialize a Notification object and then post it. Notification name and any data can be given upon initialization. Here’s how to initialize a notification without data:

And here’s how to initialize a notification with data:

object expects for a single value of Any type and it can be nil.

userInfo is an optional value too and it expects for a dictionary into which you can have as much data as you want.

Note: AnOptionalObject and AnOptionalDictionary are fake values.

To send the notification, simply call:

All the above is an unnecessary effort as notifications can be created and sent in one line only. Simply use any of the following:

  • post(name:object:): It creates and posts a notification with an optional object (Any object). Keep it nil if you don’t want to post any data along with the notification.
  • post(name:object:userInfo:): It creates and posts a notification with an optional object or a dictionary. It’s similar to the equivalent notification initializer. Pass nil as an argument to any parameter (object or userInfo) you don’t want to send data for.

The last one is what I always prefer to use, as it’s the most flexible option and easy to change during development. Let’s modify the updateParent() method as follows:

The above will post the .didCreateShoppingList (Notification.Name.didCreateShoppingList) notification and it will include the items collection as the notification’s object every time we tap on the back button in the ShoppingListViewController. We set nil to the userInfo dictionary, there’s nothing more to post.

Handling the Notification

Let’s switch to the AllListsViewController.swift file, and let’s start by observing for the above notification. Go to the viewDidLoad() method and add the following line:

With that line, we are adding our class as an observer of the didCreateShoppingList notification to the Notification Center, and we’re telling our app to call the handleDidCreateShoppingList(notification:) method upon receiving it. This method doesn’t exist yet, so let’s go straight ahead to create it.

Still in the AllListsViewController class, add the following:

The first thing we do here is to make sure that the object property of the notification has an actual value. Always do that check and never use the object property directly if you want to be safe and away from app crashes. At the same time, and if object is not nil, we cast it to an array of String objects, as the didCreateShoppingList notification brings along the collection of items added to the shopping list.

The rest of the code is specific to the demo app we’re building. We create a new ShoppingList object that will get the proper ID, the default list name, the current timestamp and the items collection. That object is added to the lists collection of the listManager object in the AllListsViewController view controller, and finally the tableview is reloaded so we visually reflect any changes made.

If we run the app at this point and we create a new shopping list, it will be listed in the AllListsViewController view controller.

t62_5_keep_list

Completing Implementation With A New Notification

Now that we made it possible to save and show a new shopping list in the AllListsViewController view controller, let’s keep on working on the same logic and create a new notification that will enable us to update shopping lists properly. By testing our demo app on its current state, we can see that it’s possible to edit an existing shopping list, however every time we go back to the initial screen the list is not updated; a new entry is being created instead.

t62_6_add_instead_of_update

That behaviour is pretty much expected, as the only thing that happens when we tap on the back button in the ShoppingListViewController class is the notification posting that “says” to AllListsViewController to create a new shopping list. So, it’s necessary to go back to ShoppingListViewController.swift file and revisit the updateParent() method to change that.

We will update that method based on a single fact:

When a new shopping list is being created, the shoppingList property in ShoppingListViewController has no id value (it is nil). On the contrary, when a shopping list is being edited the id property of the shoppingList object has a value and it is not nil.

You can verify that in the prepare(for:sender:) method in the AllListsViewController class, where if a list has been selected (selectedListIndex is other than nil), the id of the shopping list is passed along with other values to the shoppingList property of the ShoppingListViewController:

So, now that we know that, it’s time to change the updateParent() method as shown next:

In human words, if the shopping list has an id value, then that means that we are updating it and we are posting a brand new notification (didUpdateShoppingList). Otherwise, we are talking about a shopping list that we just created and the notification we sent in the previous part will be posted. Pay attention to that new notification:

Two noticable things here:

  • The first is the notification name, which is obviously different than the first one.
  • The second is that we are not using the object parameter value here. Instead, we are making use of the userInfo dictionary and we pass two different kind of data: The id of the edited shopping list, and the items collection.

In the AllListsViewController.swift file now, let’s update the viewDidLoad() method so we make it possible to observe for that new notification:

This time, we call the handleDidUpdateShoppingList(notification:) method when the didUpdateShoppingList notification gets received. Our next task is to implement it:

Note that it’s necessary to make sure that the userInfo dictionary is not nil before proceeding. After that, we just update the list in the shopping lists collection of the listManager, and we reload the tableview.

Build and run the app again. This time you’ll see that when you edit a shopping list and then go back to the first view controller, it is properly shown in the tableview. Moreover, the last updated list is shown to the top.

t62_7_properly_edit_lists

Before continuing to the next part, one last thing: Stop your class from observing for notifications when it’s about to be destructed (deallocated). In the demo app where we observe for notifications in a view controller, here’s how we do that:

Add the above to the AllListsViewController class right after the viewWillAppear(_:) method.

Closures

Apart from delegation pattern and notifications, there is one more straightforward, less used probably, method to send messages among classes in an app: Closures and action handlers. Most probably, the nature of writing closures is what it makes it less attractive. That shouldn’t be happening though; the powerfulness of this method can be seen once someone understands how to write them.

To have a first understanding about how this approach works, think again of the two hypothetical classes we talked about earlier, ClassA and ClassB, where ClassB is the one that needs a way to talk back to ClassA.

In its simplest form, ClassB implements a method where at least one parameter is a closure:

Think of it like that: You pass a function as the parameter of another function. In this example, handler: () -> Void is the function parameter. In this case it has no arguments, and it’s a void function, something that must be explicitly declared.

Why @escaping? Shortly, so we can access the action handler (the closure) after the execution of the method has finished. Read more here.

Next, myMethod(handler:) keeps a reference to the the handler parameter in a class property, so it can be called when it’s necessary for ClassB to communicate with ClassA.

This can happen if only the class property’s type is the exact handler declaration:

It’s an optional value, as by default it points to nothing.

Here is how myMethod(handler:) keeps the reference to the handler function:

Later on, ClassB calls the action handler when it’s about time to communicate with ClassA. The only almost mandatory thing is to make sure that the action handler property is not nil:

One the other side now, when ClassA calls myMethod(handler:) through the initialized ClassB object, it implements a closure, meaning a block of code that it won’t be executed unless the handler function is called in ClassB:

The above could be written also as:

Data can be passed from ClassB to ClassA, as long as the matching parameter values are declared in the handler functions. For example:

Calling it:

The purpose here is to get the big picture, so don’t worry about the details or if you don’t fully get it. We are going to see specific examples right next. Before we get there though, here’s a popular iOS SDK’s method that uses action handlers:

The above is one of the simplest ways to perform animations on iOS, and there are serious chances that you have seen something similar or written animations already, so most probably it looks familiar. The specific code above is taken straight from the demo app, and it can be found in the AllListsViewController, showRenameListView() method.

See that there are two handlers here: One that is called to perform the actual changes in the UI that produce the desired animation (animations closure), and one to notify that animation is finished (completion closure).

An action handler being last in a method or function is usually called completion handler because most of the times it signals the end of some process.

Before we focus again on the demo app, you are encouraged to make a search on the Internet about closures, action and completion handlers so you have a better understanding of everything discussed here.

Action Handlers In… Action

After that introductory discussion above, let’s become specific again and let’s talk about our demo app. Our goal in this part is to enable renaming of shopping lists.

In the starter project, a swipe-left gesture on a list in AllListsViewController reveals two options that allow to rename and delete the selected shopping list. So far, a custom view called RenameListView shows up when tapping on the Rename context button of any shopping list cell, but none of the Rename or Cancel buttons in it work. And our mission is to change that.

t62_8_rename_delete_options

We will start working in the RenameListView.swift file. As said, RenameListView is a custom view implementation that we will use to rename any shopping list.

As a first step, let’s make our cancel button work. In the beginning of the RenameListView class, add the following declaration:

The above property will keep the reference to the actual action handler, which is also the one and only parameter of the following method (add it to the RenameListView class too):

The handleCancelRenaming(handler:) method will be called through the AllListsViewController class in a while. Here we just define it, but it’s crucial to keep the action handler out of the scope of that method so we can access it later on. That’s why we assign it to the cancelHandler property.

Note: Consider the above two steps as a standard procedure when you implement action handlers as a communication solution among classes. Of course, naming won’t be the same, as well as any potential parameters in action handlers. Despite that, logic remains always the same!

The third and last step here is to call the cancelHandler handler when the Cancel button is tapped. Go to the cancel(_:) IBAction method that has been defined already in the starter project, and update it as shown next:

Since cancelHandler was originally declared as an optional, it’s really vital to make sure that it is not nil.

What we did so far doesn’t mean that the RenameListView will actually disappear; there is no code for that! All we did was to make it possible to call an action handler when the Cancel button gets tapped. We are still missing the implementation of that action handler.

Open the AllListsViewController.swift file, and go to showRenameListView() method. There is already some code in the body of that method, and it’s the place where renameListView, a RenameListView class object is being initialized and makes the respective view appear when the Rename context button is tapped on a cell.

At some point in that method you’ll find a comment saying: “// Add action handlers here!”. Go a couple of lines after it, and call the handleCancelRenaming(handler:) method through the renameListView object. While you’ll be typing, Xcode will auto-suggest it. Just hit Return to get the following:

And our closure is there! Let’s make renameListView disappear:

Note: self is necessary when referencing class properties or methods through closures.

The Cancel button in the rename view is fully working now! And if you think about it, RenameListView class says to AllListsViewController when to make it disappear, so our goal has been achieved!

We are not done yet though. Let’s follow the same process, and let’s enable renaming. The steps needed for that are pretty much the same as above. The only difference here is that we’ll see how to carry data around: The new shopping list name.

Back to RenameListView.swift file, let’s start by declaring the next property that will keep a reference to the rename action handler:

Next, let’s implement the following method and give AllListsViewController class the option to know when renaming takes place:

Watch the new thing here: There is a parameter in the handler method.

In the rename(_:) IBAction method we will call the renameHandler. Before we do so, we must make sure that user has typed some text. Here it is all together:

Notice that the text value is given as an argument to the action handler, which is expecting for it since we declared it that way. It is not allowed to call the handler without any arguments, or with more arguments than the expected one. You should always pass as many arguments as the parameter values in the handler declaration are!

Our work in the RenameListView class is done. Let’s pay a final visit to AllListsViewController.swift file, and in the showRenameListView() method again. Right below the implementation of the previous action handler, add the following:

In the above snippet, we first make sure that the index to the edited list exists, and then we access that list through the listManager property and we update its name. Of course, we also reload the table view so the new name gets displayed. But besides all that, the most important thing is the way closure is written when there’s a parameter (or more) in the handler, and how that parameter is used.

That’s it, try the app again now and rename your shopping lists!

delegates, closures demo

Conclusion

Our journey on how to implement communication internally in apps has come to its end. After you comprehend what you read here, most probably you will start wondering which method to choose when it’s about time to use them in your own projects. The answer is that there are no clear rules, and you choose what fits best to your app. As a rule of thumb, the order in which the three different approaches were presented here should also be the order of your preference.

Delegation can be used pretty much everywhere, but notifications could be proved a simpler and faster implementation in certain circumstances, for example when data fetching from a server is finished and you want to notify the view controller that is going to display it. Closures are powerful too and ideal for keeping everything in one place, or when implementing delegation or notifications seem to be an overkill for small objectives.

Undoubtedly, experience will be your guide, so the more you use them and the more use cases you meet, the easier for you to decide. I hope you enjoyed this post, and if so, share it! Thanks for reading, see ya!

For reference, you can download the complete project on GitHub.

macOS
macOS Programming Tutorial: Working with Collection View
Tutorial
Using AsyncDisplayKit to Develop Responsive UIs in iOS
Tutorial
How to Resolve “Couldn’t instantiate class named WKWebView” Error When Using WebKit
Shares