티스토리 뷰

728x90

타입으로서의 프로토콜 (Protocols as Types)

 

프로토콜은 기능구현을 하지 않습니다. (선언만 할 뿐)

프로토콜을 타입으로 사용할 수 있습니다.

다른 타입이 허용되는 여러 곳에서 다음과 같은 프로토콜을 사용할 수 있습니다.

 

  • 함수, 메서드 또는 이니셜라이저에서의 매개변수 타입 또는 리턴타입
  • 상수, 변수 또는 프로퍼티로서의 타입
  • 배열, 사전, 다른 컨테이너의 항목으로서의 타입

 

타입이기 때문에 네이밍은 첫번째 문자를 대문자로 해줍니다.

ex) TestType

 

예제로 바로 봐봅시다

 

protocol RandomNumberGenerator {
    
    func random() -> Double
    
}

class LinearCongruentialGenerator: RandomNumberGenerator {
    var lastRandom = 42.0
    let m = 139968.0
    let a = 3877.0
    let c = 29573.0
    func random() -> Double {
        lastRandom = ((lastRandom * a + c).truncatingRemainder(dividingBy:m))
        return lastRandom / m
    }
}

class Dice { // <- 채택 안함
    
    let sides: Int
    let generator: RandomNumberGenerator // 타입지정
    
    init(
        sides: Int,
        generator: RandomNumberGenerator
    ) {
        self.sides = sides
        self.generator = generator
    }
    
    func roll() -> Int {
        return Int(generator.random() * Double(sides)) + 1
    }
    
}

var d6 = Dice(sides: 6, generator: LinearCongruentialGenerator())
for _ in 1...5 {
    print("Random dice roll is \(d6.roll())")
}

 

여기선 채택을 해주지 않고 generator라는 상수에 RandomNumberGenerator를 타입으로 지정해줬습니다.

그리고 Dice class 안에 sides, generator의 초기값이 없어 init으로 초기값을 지정해주고,

generator는 RandomNumberGenerator 타입이기 때문에 .(dot 문법)으로 random()에 접근할 수 있게 됩니다. 

 


위임 (Delegation)

 

Delegate 패턴을 공부하면서 처음 접하게 됐던게 Protocol이었는데요.

다시한번 정리해보겠습니다.

 

Delegation은 class나 struct가 책임을 일부 다른 타입의 인스턴스로 전달 할 수 있게하는 디자인 패턴 입니다.

 

 

대표적으로 많이 사용하는 예시로 다시 설명하자면,

 

데이터를 보낼 쪽에서 프로토콜을 선언하고, delegate를 선언합니다.

// DetailVC

// 1. 프로토콜 선언
protocol CountDelegate: AnyObject {
    func plusCount(count: Int)
}

class DetailViewController: UIViewController {

    weak var delegate: CountDelegate? // 2. delegate 선언

    var count: Int = 0

    override func viewDidLoad() {
        super.viewDidLoad()
        print(self)

    }

    @IBAction func tappedButton(_ sender: UIButton) {
        count += 1
        delegate?.plusCount(count: count)
    }

}

 

 

데이터를 받는 쪽에서 해당 프로토콜을 채택하면, 프로토콜 내용(메서드, 프로퍼티)을 필수로 갖게 합니다.
해당 메서드, 프로퍼티를 통해 두번째 뷰 (DetailVC)로 부터 데이터를 받을 수 있습니다. 

// MainVC

class MainViewController: UIViewController {

    @IBOutlet weak var buttonTappedCountLabel: UILabel!
    @IBOutlet weak var countLabel: UILabel!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard let detailVC = segue.destination as? DetailViewController else { return }
        
        detailVC.delegate = self   // 1-2. ⭐️ 까먹지말고 delegate 위임해 줄 곳을 지정해주자
        print("detailVC:\(detailVC)")
    }
    
}

extension MainViewController: CountDelegate { // 1. 프로토콜 채택
    func plusCount(count: Int) {  // 2. 프로토콜 채택으로 필수 메서드 plusCount(count:) 구현해야함
        countLabel.text = "\(count)"  // 3. 두번째뷰 (DetailVC)의 데이터를 가져올 수 있음
    }
    
    
}

여기까지 ! 

다음엔 protocol extension에 대해 정리해 보겠습니다!!

728x90