Skip to content

Latest commit

 

History

History
282 lines (177 loc) · 7.87 KB

File metadata and controls

282 lines (177 loc) · 7.87 KB

Communication Patterns

Why you should know this

If we think about how apps work, we can see they're usually multiple screens displaying or passing information.

In this last remark, there are several methods or patterns we can use to achieve communication between elements in an app.

Learning Objectives

  1. Identify and implement the Target-Action pattern for event handling.
  2. Understand how Notifications work using Notification Center.
  3. Analyze and decide which pattern to use based on the requirements of an app.

Target-Action

Target-Action is a design pattern in which an object holds the information necessary to send a message to another object when an event occurs.

It's the pattern used to send messages in response to user-interface events, specifically from UIControl.

Simplifying things

The Target-Action object has:

  1. Target - The object that will be notified
  2. Action - The method that will be used
  3. Event that will trigger the Target-Action

Buttons are an example of this pattern, they send a message when they have been tapped.

If the target is specified then the action message, it is sent to the object.

What are selectors?

Unrecognized selector sent to instance

Wave you ever seen this error in which the app crashes?
What was the problem?

A: Xcode couldn't find the method being called 😰

Selectors are the names of methods used to execute code at runtime.

The name of the method that will be called and the object to send the message to are not known until runtime.

Selectors are not part of the default Swift runtime behavior so we include @objc to our methods.

How does this look like?

Creating a UIButton

let loginButton = UIButton(type: .roundedRect)
loginButton.setTitle("Login", for: .normal)

Adding the target

loginButton.addTarget(self, action: #selector(login), for: .touchUpInside)

Created a UIButton and called addTarget(_:action:for:) with these parameters:

  1. target is self
  2. action is #selector(login)
  3. event is .touchUpInside

When the event .touchUpInside occurs, send a message to self to execute login

Here's the method called

@objc func login(){
  print("Button tapped")
}

Variation passing in the sender object

loginButton.addTarget(self, action: #selector(login(sender:)), for: .touchUpInside)

@objc func login(sender: UIButton){
  print("Button tapped")
  //Because you received the sender as a parameter, you can access its properties.
  print(sender.titleLabel?.text)
}

Example

Playground example

Something to note is that the messages sent can't carry custom information. Which is why we can't send values in a UIButton's target action. They could send the sender that triggered the action as an argument, but that is as far as it goes.

Passing arguments in the target action

CustomButton Replit

Notifications 📣

Notifications can broadcast messages between relatively unrelated parts of your code. They use the Observer pattern to inform registered observers when a notification comes in, using a central dispatcher called Notification Center.

The Notification Center deals with registering observers and delivering notifications.

Notifications can include a payload in form of their property called userInfo, which is a dictionary.

The sender and the recipient don’t have to know each other so they are useful to send information between very distant modules.

How the Notification Center works

Has 3 components

  • An observer that listens for notifications
  • A sender that sends notifications when something happens
  • The notification center that keeps track of observers and notifications

notification

Registering for notifications

This adds an entry to the Notification Center.

print("Added Observer")
NotificationCenter.default.addObserver(self,
  selector: #selector(receivedNotification(_:)),
  name: Notification.Name("receivedNotification"),
  object: nil)
@objc func receivedNotification(_ notification:Notification) { // Do something here print("Received notification") self.view.backgroundColor = UIColor.purple }

Posting notifications

Needs the name of the notification and the object that posts the notification.

print("Post Notification")
NotificationCenter.default.post(
  name: Notification.Name("receivedNotification"),
  object: self)

Unsubscribing

⚠️ Observers need to be removed, or else you send a message to something that doesn't exist.

deinit {
  print("Removed Observer")
  NotificationCenter.default.removeObserver(self,
    name: Notification.Name("receivedNotification"),
    object: nil)
}

A deinitializer is called immediately before a class instance is deallocated. Swift automatically deallocates your instances when they are no longer needed, to free up resources.

Practice - Checking for understanding

Notifications syntax practice - Replit

Tips

  • When creating a notification, use unique names that are also helpful.
  • It's best if you declare a constant for the name.
  • Use the name of the Notification for the selector method. This is less confusing.
  • Do not overuse this communication pattern or you'll end up with too many dependencies
  • Use Notifications when you need to communicate between 2 or more objects in the app that don't know about each other. Or when using one-to-many or many-to-many communications that are consistent.

Pomodoro App

  1. Learn what the Pomodoro technique is: go to video

  2. Then follow the instructions in this repo.

  3. Submit your completed version to Gradescope.

Self Study - suggested resources

Additional Resources

  1. Selector and extensions
  2. Target- Action Apple Archives
  3. Target-Action - article
  4. Notifications
  5. Notifications