iOS & Swift 공부 - More on Swift Delegate Design Pattern

김영채 (Kevin)·2021년 1월 18일
0

iOS & Swift

목록 보기
33/107

Extra Notes on Swift Delegate Protocol Pattern

  • It's super important to know when you want two views to communicate with each other (1:1)

Example app → left: base screen, right: selection screen / When side is chosen, the base screen shows a different screen depending on the user selection

  • When thinking about delegate patterns, think about a boss and intern. Here, the base screen is the "intern" and the selection screen is the "boss".
  • In the above example, the boss is the one who knows all the info. It knows what the user selected, what side it is, what image to present, etc. The intern doesn't know a thing. The boss will pass the info to the intern and accordingly, the intern will act as the boss told him to do.

Q. How to know which is the intern and which is the boss?

A. Which one "knows" all the information? → Boss / Which screen is just "acting" based on the information? → Intern

Steps:

  • First, define a protocol in the boss screen. It will be like a list of commands that you will give to the intern.

    → Think of it as a command list for our intern

//SelectionScreen.swift

protocol SideSelectionDelegate{
	func didTapChoice(image: UIImage, name: String, color: UIColor)
}
  • Then, our SelectionScreen class must have a variable to hold the above Delegate
class SelectionScreen: UIViewController{

	var selectionDelegate: SideSelectionDelegate!
	//Our intern's name is selectionDelegate!
	//Notice we are not setting this to anything. We are going to set its actual value in the base screen
	//So, we named our intern, but we didn't actually "make" it. 
	
	override func viewDidLoad(){
		super.viewDidLoad()
	}

	@IBAction func imperialButtonTapped(_ sender: UIButton){
		dismiss(animated: true, completion: nil)
	}
	@IBAction func rebelButtonTapped(_ sender: UIButton){
		dismiss(animated: true, completion: nil)
	}

}
  • Next, we have to give our intern, which is selectionDelegate, some orders when the buttons are tapped.
@IBAction func imperialButtonTapped(_ sender: UIButton){

		selectionDelegate.didTapChoice(image: UIImage(named: "Vadar")!, name: "Darth Vader" , color: .red)
		//Boss: Hey intern, the imperialButton has been tapped, hold these 3 parameters (info) for me
		//so you can do stuff
		dismiss(animated: true, completion: nil)
}

@IBAction func rebelButtonTapped(_ sender: UIButton){

		selectionDelegate.didTapChoice(image: UIImage(named: "Luke")!, name: "Luke Skywalker" , color: .cyan)
		dismiss(animated: true, completion: nil)
}
  • We now go to the intern screen (Base Screen)
class BaseScreen: UIViewController{

	@IBOutlet var mainImageView: UIImageView!
	@IBOutlet var chooseButton: UIButton!
	@IBOutlet var nameLabel: UILabel!

	@IBAction func chooseButton(_ sender: UIButton){
		let selectionVC = storyboard?.instantiateViewController(withIdentifier: "SelectionScreen") as! 
		SelectionScreen

		selectionVC.selectionDelegate = self //I would like to be your intern

		present(selectionVC, animated: true, completion: nil)
	}
}

→ In the base screen (intern), it just gets information from the boss, and shows it.

  • selectionVC now has the conform to the Delegate. So a way is to write an extension
extension BaseScreen: SideSelectionDelegate{
	
	//This function gets called automatically when either of the 2 buttons from the boss screen
	//gets tapped. So you don't have to manually call the below function in the intern screen
	//This is where the intern actually does the work after the boss passes the info needed
	func didTapChoice(image: UIImage, name: String, color: UIColor){
		mainImageView.image = image   //The info is passed, so we assign the value from the parameter
		nameLabel.text = name
		view.backgroundColor = color

	}
}

→ Our intern just performs the job, setting the screen value, after the boss passes the information

  • Full code for base screen below
class BaseScreen: UIViewController{

	@IBOutlet var mainImageView: UIImageView!
	@IBOutlet var chooseButton: UIButton!
	@IBOutlet var nameLabel: UILabel!

	@IBAction func chooseButton(_ sender: UIButton){
		let selectionVC = storyboard?.instantiateViewController(withIdentifier: "SelectionScreen") as! 
		SelectionScreen

		selectionVC.selectionDelegate = self 

		present(selectionVC, animated: true, completion: nil)
	}
}

extension BaseScreen: SideSelectionDelegate{

	func didTapChoice(image: UIImage, name: String, color: UIColor){
		mainImageView.image = image   
		nameLabel.text = name
		view.backgroundColor = color

	}
}
profile
맛있는 iOS 프로그래밍

0개의 댓글