본문 바로가기

iOS

[iOS] Protocol 학습 및 delegate패턴 사용해보기

프로토콜이란?

기능의 조각 또는 특정 직무를 입히는 다른 요구사항들과 메서드 프로퍼티들의 청사진이다.
=> 프로토콜을 채택하는 타입은 이런 프로퍼티와 메서드를 가지는걸 보장합니다 라는 자격증과 비슷하다.
=> 프로토콜은 타입을 묶는 용도로도 사용하고 타입간의 결합도를 낮추기 위해도 사용한다.

[특징]

- 프로토콜은 열거형, 클래스, 구조에 의해 채택될 수 있다.

- 프로퍼티는 get인지 get set인지를 구분해주며 메서드는 이름과 매개변수 및 반환타입까지만 지정하- 여 본문은 구현하지않는다.

- 프로퍼티 선언지 let선언이 안되는이유 중 하나는 연산프로퍼티는 let으로 설정할 수 없다.

- getter는 무조건 가져야하며. set만 설정하면 variable with a setter must also have a getter라는 오류 메세지가 나온다.

- 타입프로퍼티는 static을 사용하고 class와 static을 구분하지않으며 class가 붙으면 상속시 서브클래스에서 재정의가 가능하다.

- gettable은 읽을 수 있으며 get set은 읽고 쓸수있는 기능을 가지는데 get이 읽기 전용만을 의미하지는 않는다. 실제로 채택받아서 사용할때 읽고 쓰기 모두 사용해도 문제가 없다.

- 프로퍼티에 get set을 설정받은 프로토콜을 채택하여 사용할때 프로퍼티를 get속성만으로 사용하게되면 준수하지못하다는 컴파일 오류가 난다. set의 속성을 넣어주는 이후로는 읽기 전용으로 사용할 수 없다는 것이다.

- get set중 get만 설정해놓으면 타입에서 채택받아서 사용할때 let을 설정할 수도 있다. 추가로 private(set)으로도 설정이 가능한데 private으로는 설정할 수 없다. 왜냐하먄 읽을 수 있는 자격이 있는건데 예를들어서 자동차운전면허를 땃는데 보여줘야 증명이되지 보여질 수 없으면 get이라는 성질의 의미가 없어지기 때문이다.

- protocol은 타입으로도 사용할 수 있으며 &을 이용하여 여러프로토콜을 중첩하여 사용도 가능하다. ex) let quokka: FullyName&Animal

- protocol을 채택한 내부의 기능들은 사용할 수 있으나 타입은 사용될 수 없다. 그럴땐 다운캐스팅으로 사용해 볼 수 있다.

- protocol내에 메서드를 정의할때 mutating을 붙여주면 채택받은 타입내에서 메서드를 사용할때 mutating을 안붙여줘도된다.

- class의 경우 init을 가지는 프로토콜을 재택하였을때 required를 붙이는게 필수로 요구된다. 하지만 final class는 필수로 요구되지않는다.

[프로토콜의 사용시 유의할점]

SOLID원칙 중 하나인 타입은 하나의 타입만을 준수하여 결합도를 낮춘다. 이는 코드 수정에 매우도움이되며 유지보수에 좋다.
그렇다고 모든 타입을 프로토콜을 사용하는게 좋을까 ??? 또 그렇지는 않다. 무조건 프로토콜 먼저 만들어 버린다고 하면 오버 엔지니어링이 발생할 수 있다. 정말 확장 가능성이 적은데 프로토콜로 확장가능성을 시도한다면 인력 및 시간낭비가 발생할 수 있다. 그래서 적절히 고려해야할 필요가 있다. 고로 무조건 결합도가 높다고 해서 안좋고 낮다고해서 좋다고 볼 수 는 없는것이다. 그치만 연습하는 입장에서는 결합도를 낮춰보는 연습이 필요한건 사실이기때문에 결합도를 낮춰보는 연습을 시도해보고 현업에 가서는 사용해야할 필요가 있는지 적절히 고려해보는것이 좋을것 같다.

# Delegate(위임)

[정의]

  • 위임은 클래스나 구조체가 일부책임을 다른 유형의 인스턴스에 넘길 수 있도록 하는 디자인 패턴이다.

Delegate이용한 데이터 전달

[SecondView에서 FirstView로 돌아올때 데이터를 전달하면서 창을 닫는다.]

[첫번째 뷰에서 하는일 ] 
- protocol 채택
- 실제구현
- 대리자 위임

extension UIViewController {
    static var identifier: String {
        return String(describing: self)
    }
}

class FirstViewController: UIViewController, DeliveryDataProtocol {
    func deliverydata(_ data: String) {
        dataLabel.isHidden = false
        dataLabel.text = data
    }
    @IBOutlet weak var dataLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .blue
        dataLabel.isHidden = true
        dataLabel.textColor = .white
    }
    
    @IBAction func moveSecondView(_ sender: Any) {
        guard let secondVC = self.storyboard?.instantiateViewController(withIdentifier: SecondViewController.identifier) as? SecondViewController else { return }
        secondVC.delegate = self
        present(secondVC, animated: true, completion: nil)
    }
 
[두번째 뷰에서 하는일]
- 타입이 protocol인 property생성
- delegate사용

protocol DeliveryDataProtocol: AnyObject {
    func deliverydata(_ data: String)
}

class SecondViewController: UIViewController {

    var delegate: DeliveryDataProtocol?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = .yellow
    }
    @IBAction func dissmissButton(_ sender: Any) {
        delegate?.deliverydata("오늘 하루도 화이팅입니다!!")
        dismiss(animated: true, completion: nil)
    }
}

// 출력결과 -> FirstView에서 -> SecondView이동 -> SecondView화면닫기 -> FirstView에 "오늘 하루도 화이팅입니다!!" 데이터가 출력

 

- Reference

- 델리게이트 패턴활용