[iOS] Segue Action으로 생성자 주입 사용해보기

RudinP·2024년 6월 19일
0

Study

목록 보기
230/258
class PlanetDetailViewController: UIViewController {
    @IBOutlet weak var backgroundImageView: UIImageView!
    
    var planet: Planet? //ViewController 생성 시 해당 값을 채울 수 없기 때문에 optional
    ...
...
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let cell = sender as? UICollectionViewCell, let indexPath = planetCollectionView.indexPath(for: cell){
            let selected = solarSystemPlanets[indexPath.item]
            
            if let vc = segue.destination as? PlanetDetailViewController{
                //의존성 주입
                vc.planet = selected
            }
        }
    }
  • iOS 앱개발에서 prepareForSegue에서 Property Injection을 하는 방식은 꾸준히 사용되어오는 패턴이다.
  • iOS13버전 이전에서 Property Injection이 아닌 Initialization Injection을 사용하려면 Segue를 사용하지 못하고 코드로 구현해야 한다.
    뷰 컨트롤러를 만들고 화면을 전환하는 것까지 말이다. 왜냐하면, Segue는 destination vc를 자동으로 만드는데 원하는 생성자를 호출하거나 vc 생성자로 내가 원하는 파라미터를 전달하는 방법이 없기 때문이다.
  • 이러한 문제 때문에 iOS13에서 Segue Action이 도입되었다.
  • 해당 방법을 통해 VC를 자동으로 생성하는 부분을 제어할 수 있게 되었다.

Segue Action

storyboard에서 연결

  • segue를 ctrl+drag하여 Segue Action을 추가 가능하다.

destination VC 생성자 추가

class PlanetDetailViewController: UIViewController {
    @IBOutlet weak var backgroundImageView: UIImageView!
    
    private let planet: Planet
    
    init?(planet: Planet, coder: NSCoder){
        self.planet = planet
        
        super.init(coder: coder)
    }
    
    //failable initializer
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        let img = UIImage(named: planet.englishName.lowercased())
        backgroundImageView.image = img
        
    }
  • 여기서 initializer을 추가할 때 required Initializer, failable Initializer 에러가 발생한다.
  • vc의 init을 만들 때 반드시 required init? 생성자를 overrider 해야하며, 실제 init 추가시에도 이 형식에 맞춰 init?으로 작성해야 하며, 반드시 인자에 codeR:NSCoder을 포함해야 한다.

segueAction에서 destination VC init? 호출

class MainViewController: UIViewController {
    @IBOutlet weak var planetCollectionView: UICollectionView!
    
    @IBSegueAction func makeDetailVC(_ coder: NSCoder, sender: Any?) -> PlanetDetailViewController? {
        guard let cell = sender as? UICollectionViewCell, let indexPath = planetCollectionView.indexPath(for: cell) else {
            return nil //segue가 vc를 자동으로 만듦. 즉, PlanetDetailViewController의 required init?을 호출하고 크래시가 발생할 것.
        }
        
        let selected = solarSystemPlanets[indexPath.item]
        return PlanetDetailViewController(planet: selected, coder: coder)
    }
  • NSCoder는 스토리보드에서 VC를 만들 때 필요한 객체이다.

Property Injection과 차이

  • PI가 이해가 쉽고 구현 코드 양이 적음
  • PI가 iOS 13 이전과도 호환성이 좋음
  • PI가 은닉성이 떨어짐
  • 변수 속성이 선언하고 optional이 강제됨
profile
iOS 개발자가 되기 위한 스터디룸...

0개의 댓글