์ƒˆ์†Œ์‹

๐Ÿ“ฑ iOS/-- UIKit

(iOS) ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ํŒจํ„ด (Delegate Pattern , tableView , TextField, ํ™”๋ฉด๊ฐ„ ๋ฐ์ดํ„ฐ ์ „๋‹ฌ)

  • -

Delegate Pattern

 

iOS ๊ฐœ๋ฐœ ํŒจํ„ด์ค‘ ๊ฐ€์žฅ ์ค‘์š”ํ•œ ํŒจํ„ด์ด๋‹ค. Apple framework๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐ˜๋“œ์‹œ ์•Œ์•„์•ผํ•  ํŒจํ„ด์ด๋‹ค.

  • ์–ด๋–ค ๊ฐ์ฒด์™€, ๊ฐ์ฒด์˜ ๊ธฐ๋Šฅ์„ ๋Œ€์‹  ์ˆ˜ํ–‰ํ•  ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ฐ์ฒด๊ฐ€ ํ•„์š”ํ•˜๋‹ค.
  • ์˜ˆ๋ฅผ๋“ค๋ฉด, ์ƒํ’ˆ์„ ํ‘œ์‹œํ•˜๋Š” TableView๋ฅผ ํ„ฐ์น˜ํ•˜๋ฉด, ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์žˆ๋‹ค๊ณ  ํ•œ๋‹ค. ์ด๋•Œ, ์‚ฌ์šฉ์ž๊ฐ€ TableView๋ฅผ ์„ ํƒํ–ˆ์„๋•Œ, TableView๊ฐ์ฒด๋Š” ์–ด๋–ค ๊ธฐ๋Šฅ์„ ์‹คํ–‰ํ•ด์•ผ ํ• ์ง€ ๋ชจ๋ฅธ๋‹ค. ๋”ฐ๋ผ์„œ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ฐ์ฒด๊ฐ€ ์ด(์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•˜๋Š” ๊ธฐ๋Šฅ)๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค.

 

  • ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” TableView ๊ฐ์ฒด๋Š” ...dataSource ํ˜น์€ ...delegate ๋ผ๋Š” ์ ‘๋ฏธ์–ด๋ฅผ ๊ฐ€์ง„๋‹ค.
  • ์‚ฌ์šฉ์ž๊ฐ€ TableView๋ฅผ ํ„ฐ์น˜ํ•˜๊ฒŒ ๋˜๋ฉด, TableView๋Š” ์ง์ ‘ ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•˜์ง€ ๋ชปํ•˜๋ฏ€๋กœ, ๋Œ€๋ฆฌ์ž์˜ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๊ณ , ์ด๋•Œ ๋Œ€๋ฆฌ์ž(๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ฐ์ฒด)๊ฐ€ ๋Œ€์‹  ๊ธฐ๋Šฅ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค.
  • ํŠน์ • ์ด๋ฒคํŠธ ๋•Œ ํ˜ธ์ถœ๋˜๋Š” ๋ฉ”์†Œ๋“œ๋Š” ํ”„๋กœํ† ์ฝœ์— ์„ ์–ธ๋˜์–ด์žˆ์–ด์•ผ ํ•œ๋‹ค.
  • ๊ทธ๋ฆฌ๊ณ  ๋‹น์—ฐํžˆ ํ”„๋กœํ† ์ฝœ์— ์„ ์–ธ๋˜์–ด์žˆ๋Š”๊ฒƒ๊ณผ ์ผ์น˜ํ•˜๊ฒŒ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์•ผํ•œ๋‹ค.

(ํ…Œ์ด๋ธ”๋ทฐ๊ฐ™์€ ๊ฒฝ์šฐ์—๋Š”, ๋ณดํ†ต ์ž์‹ ์„ ํฌํ•จํ•˜๊ณ  ์žˆ๋Š” ๋ทฐ์ปจํŠธ๋กค๋Ÿฌ๋ฅผ ๋Œ€๋ฆฌ์ž๋กœ ์ง€์ •ํ•œ๋‹ค.)

 

๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ํŒจํ„ด์„ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

 

iOS์—์„œ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ธ๋ฆฌ๊ฒŒ์ด์…˜์„ ๊ตฌํ˜„ํ•˜๋Š” ๊ฒƒ์€ ํด๋ž˜์Šค๊ฐ€ ๋‹จ์ผ ์ƒ์†๋งŒ์„ ์ง€์›ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ์ฆ‰, ํ•˜๋‚˜์˜ ๋ถ€๋ชจ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›๊ณ  ๋‚˜๋ฉด ๋”๋Š” ๋‹ค๋ฅธ ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›์„ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ ๊ธฐ๋Šฅ์„ ๋ง๋ถ™์ด๊ธฐ์—๋Š” ์ œํ•œ์ ์ด๋‹ค. ์ด๋ฅผ ๊ทน๋ณตํ•˜๊ธฐ ์œ„ํ•ด ๊ตฌํ˜„ ๊ฐœ์ˆ˜์— ์ œํ•œ์ด ์—†๋Š” ํ”„๋กœํ† ์ฝœ์„ ์ด์šฉํ•˜์—ฌ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ ๋‹จ์œ„๋ณ„ ๊ฐ์ฒด๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

= ๊ฐœ๋ฐœ์˜ ์œ ์—ฐ์„ฑ์ด ์ฆ๊ฐ€ํ•œ๋‹ค.

 

 

๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ๊ตฌํ˜„ ์ˆœ์„œ

ios์—์„œ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ์˜ ์—ญํ• ์€ ํฌ๊ฒŒ ๋‘๊ฐ€์ง€์ด๋‹ค.

  1. ๋ฐ์ดํ„ฐ ๊ณต๊ธ‰ (์ด๋Ÿฌํ•œ ๊ฒฝ์šฐ์—๋Š” ...DataSource ๋ผ๋Š” ์ ‘๋ฏธ์–ด๋ฅผ ๊ฐ€์ง„๋‹ค.)
  2. ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ (...Delegate ์ ‘๋ฏธ์–ด๋ฅผ ๊ฐ€์ง„๋‹ค.)

๊ทธ๋ฆฌ๊ณ  ๋ชจ๋“  ์ปจํŠธ๋กค์—์„œ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ํ•„์š”๋กœ ํ•˜๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ๋“ค์–ด TextField์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ณต๊ธ‰ํ•  ํ•„์š”๊ฐ€ ์—†๊ธฐ ๋•Œ๋ฌธ์—, ...DataSource๋Š” ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค.

 

  1. ์–ด๋–ค ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ• ๋•Œ, Delegate๊ฐ€ ํ•„์š”ํ•œ ๊ฐ์ฒด์ธ์ง€ ๋จผ์ € ๊ฐœ๋ฐœ์ž ๋ฌธ์„œ์—์„œ ํ™•์ธํ•œ๋‹ค.
  2. ํ•„์š”ํ•˜๋‹ค๋ฉด, ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ•˜๋Š” ๋ฉ”์†Œ๋“œ์˜ ํ”„๋กœํ† ์ฝœ์„ ํ™•์ธํ•œ๋‹ค. (์ด๋•Œ ๊ฐœ๋ฐœ์ž ๋ฌธ์„œ์—required๋ผ๊ณ  ํ‘œ์‹œ๋œ ๋ฉ”์†Œ๋“œ๋Š” ๋ฐ˜๋“œ์‹œ ๊ตฌํ˜„ํ•ด์•ผํ•˜๋Š” ๋ฉ”์†Œ๋“œ์ด๋‹ค.)
  3. ๊ตฌํ˜„ํ•˜๊ณ ์ž ํ•˜๋Š” ๊ฐ์ฒด - Delegate ๊ฐ์ฒด ๋ฅผ ์—ฐ๊ฒฐํ•ด์ค€๋‹ค.
  4. Delegate ๊ฐ์ฒด์—์„œ ํ”„๋กœํ† ์ฝœ์„ ๊ตฌํ˜„ํ•ด์ค€๋‹ค.

 

 

TableView Delegate Pattern (์ฝ”๋“œ ๊ตฌํ˜„)

import UIKit

class ViewController: UIViewController {

  // MARK: ํ”„๋กœํผํ‹ฐ
  let myTableView = UITableView()
  let items = ["swift", "iOS", "TableView"]

  // MARK: ViewController override method
  override func viewDidLoad() {
    super.viewDidLoad()

    self.myTableView.dataSource = self
    self.myTableView.delegate = self
    self.myTableView.register(UITableViewCell.self,
                            forCellReuseIdentifier: "cell")
    self.view.addSubview(self.myTableView)

    self.myTableView.translatesAutoresizingMaskIntoConstraints = false
    self.view.addConstraint(NSLayoutConstraint(item: self.myTableView,
      attribute: .top, relatedBy: .equal, toItem: self.view, attribute: .top,
      multiplier: 1.0, constant: 0))
    self.view.addConstraint(NSLayoutConstraint(item: self.myTableView,
      attribute: .bottom, relatedBy: .equal, toItem: self.view,
      attribute: .bottom, multiplier: 1.0, constant: 0))
    self.view.addConstraint(NSLayoutConstraint(item: self.myTableView,
      attribute: .leading, relatedBy: .equal, toItem: self.view,
      attribute: .leading, multiplier: 1.0, constant: 0))
    self.view.addConstraint(NSLayoutConstraint(item: self.myTableView,
      attribute: .trailing, relatedBy: .equal, toItem: self.view,
      attribute: .trailing, multiplier: 1.0, constant: 0))
  }

}

// MARK: UITableViewDelegate
extension ViewController : UITableViewDelegate {

  func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    print(items[indexPath.row])
  }
}

// MARK: UITableViewDataSource
extension ViewController: UITableViewDataSource {

  func tableView(_ tableView: UITableView,
                  numberOfRowsInSection section: Int) -> Int {
    return self.items.count
  }


    func tableView(_ tableView: UITableView,
                  cellForRowAt indexPath: IndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        cell.textLabel?.text = items[indexPath.row]

        return cell
  }
}

 

 

 

 

Text Field Delegate Pattern

  • ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ ์ง€์ •์€ ๋ณดํ†ต viewDidLoad() ์•ˆ์—์„œ ํ•œ๋‹ค.
  • UITextFieldDelegate ์—๋Š” ํ•„์ˆ˜ ๋ฉ”์†Œ๋“œ๊ฐ€ ์—†๋‹ค.
  • ๋‹จ์ˆœํžˆ ์ž…๋ ฅ๊ฐ’์„ ๋ฐ›๋Š” ๊ฒƒ์€ ๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๊ฐ€ ํ•„์š”์—†์ง€๋งŒ, ํŠน์ • ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด ํ•„์ˆ˜์ ์ด๋‹ค.
  • ํŠน์ • ๊ธฐ๋Šฅ์€ ์ˆซ์ž๋งŒ ์ž…๋ ฅ๊ฐ’์œผ๋กœ ๋ฐ›๊ธฐ, ์ž…๋ ฅ ๋ฌธ์ž์˜ ๊ฐœ์ˆ˜๋ฅผ ์ œํ•œํ•˜๊ธฐ, ๋“ฑ๋“ฑ์˜ ์ œ์–ด๊ธฐ๋Šฅ์„ ๋งํ•œ๋‹ค.
import UIKit

class TextFieldViewController : UIViewController{

  @IBOutlet weak var inputField : UITextField!

  override func viewDidLoad(){
    super.viewDidLoad()
    inputField.delegate = self
  }
}

extension TextFieldViewController: UITextFieldDelegate {

}

 

 

Protocol Extension

๋ธ๋ฆฌ๊ฒŒ์ดํŠธ๋ฅผ ์ด์šฉํ•ด์„œ ์ด์ „ ํ™”๋ฉด์œผ๋กœ ๊ฐ’ ์ „๋‹ฌํ•˜๊ธฐ

ComposeDelegate.swift  ( ํ”„๋กœํ† ์ฝœ ์„ ์–ธ ํŒŒ์ผ )

import UIKit

protocol ComposeDelegate {
  func composer(_ vc: UIViewController, didInput value : String?)
  func composerDidCancel(_ vc: UIViewController)
}
  • delegate ์†์„ฑ์€ ๋Œ€๋ถ€๋ถ„ ์˜ต์…”๋„ ํ”„๋กœํ† ์ฝœ ํ˜•์‹์œผ๋กœ ์„ ์–ธํ•œ๋‹ค.

 

CustomDelegateViewController.swift (์ด์ „ ํ™”๋ฉด)

import UIKit

class CustomDelegateViewController: UIViewController {

    @IBOutlet weak var valueLabel: UILabel!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let vc = segue.destination.children.first as? ComposeViewController {
            vc.delegate = self
        }
    } 
    @objc func presentComposeVC() {
        performSegue(withIdentifier: "ComposeSegue", sender: nil)
    }
    override func viewDidLoad() {
        super.viewDidLoad()

        navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(presentComposeVC))
    }
}
extension CustomDelegateViewController : ComposeDelegate {
    func composer(_ vc: UIViewController, didInput Value: String?) {
        valueLabel.text = Value
    }
    func composerDidCancel(_ vc: UIViewController) {
        valueLabel.text = "Cancel"
    }
}

ComposeViewController.swift (๋‹ค์Œํ™”๋ฉด)

import UIKit

class ComposeViewController: UIViewController {

    var delegate : ComposeDelegate?

    @IBOutlet weak var inputField: UITextField!


    @IBAction func performCancel(_ sender: Any) {
        delegate?.composerDidCancel(self)
        dismiss(animated: true, completion: nil)
    }

    @IBAction func performDone(_ sender: Any) {
        delegate?.composer(self, didInput: inputField.text)
        dismiss(animated: true, completion: nil)
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.inputField.delegate = self


        if #available(iOS 13.0, *) {
            isModalInPresentation = true
        } 
    }
}

extension ComposeViewController : UITextFieldDelegate {
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        delegate?.composer(self, didInput: self.inputField.text)
        dismiss(animated: true, completion: nil)
        return true
    }
}
Contents

ํฌ์ŠคํŒ… ์ฃผ์†Œ๋ฅผ ๋ณต์‚ฌํ–ˆ์Šต๋‹ˆ๋‹ค

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๋‹ค๋ฉด ๊ณต๊ฐ ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.