수색…


리 액티브 프로그래밍이없는 MVVM

iOS 앱에서 Model-View-ViewModel (MVVM) 디자인 패턴을 사용하는 이유에 대해 간단히 설명하겠습니다. iOS가 처음 등장했을 때, Apple은 MVC (Model-View-Controller)를 디자인 패턴으로 사용하도록 제안했습니다. 모든 예제에서이를 보여 주었고 모든 첫 번째 개발자는 비즈니스 논리와 사용자 인터페이스 사이의 관심사를 훌륭하게 구분했기 때문에 모든 개발자가 사용하기에 만족했습니다. 응용 프로그램이 점점 더 복잡 해짐에 따라 새로운 문제가 적절하게 MVC (Massive View Controller)라고 불렀습니다. 모든 비즈니스 로직이 ViewController에 추가 되었기 때문에 시간이 지남에 따라 일반적으로 너무 크고 복잡해졌습니다. MVC 문제를 피하기 위해 iOS (Model-View-ViewModel) 패턴에 새로운 디자인 패턴이 도입되었습니다.

MVVM 다이어그램

위의 다이어그램은 MVVM의 모습을 보여줍니다. MVVM의 View 역할을하는 표준 ViewController + View (스토리 보드, XIB 또는 코드)가 있습니다 (나중에 텍스트보기에서는 MVVM의 View를 참조합니다). 뷰에는 비즈니스 로직이있는 ViewModel에 대한 참조가 있습니다. ViewModel은 View에 대해 전혀 알지 못하며보기에 대한 참조가 전혀 없음을 알아 두는 것이 중요합니다. ViewModel에는 모델에 대한 참조가 있습니다.
이것은 MVVM의 이론적 인 부분으로 충분합니다. 여기 에 대한 자세한 내용은 여기를 참조하십시오 .

MVVM주된 문제 중 하나는 ViewModel에 참조가없고 View에 대해 알지도 못하는 경우 ViewModel을 통해 View를 업데이트하는 방법입니다.

이 예제의 주요 부분은 반응성 프로그래밍 (ReactiveCocoa, ReactiveSwift 또는 RxSwif)없이 MVVM (보다 정확하게 ViewModel 및 View를 바인딩하는 방법)을 사용하는 방법을 보여줍니다. 참고 사항 : 리 액티브 프로그래밍을 사용하려면 MVVM 바인딩이 사용하기 쉽기 때문에 리 액티브 프로그래밍을 사용하는 것이 훨씬 좋습니다. 그러나이 예제는 리 액티브 프로그래밍없이 MVVM을 사용하는 방법에 관한 것입니다.

MVVM을 사용하는 방법을 보여주는 간단한 예제를 만듭니다.

MVVMExampleViewController 는 레이블과 버튼이있는 간단한 ViewController입니다. 버튼을 누르면 레이블 텍스트가 'Hello'로 설정되어야합니다. 사용자 상호 작용에 대해 무엇을할지 결정하는 것이 비즈니스 로직의 일부이기 때문에 ViewModel은 사용자가 버튼을 누를 때 수행 할 작업을 결정해야합니다. MVVM의 뷰는 비즈니스 로직을 수행하지 않아야합니다.

class MVVMExampleViewController: UIViewController {
    
    @IBOutlet weak var helloLabel: UILabel!
    
    var viewModel: MVVMExampleViewModel?
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    @IBAction func sayHelloButtonPressed(_ sender: UIButton) {
        viewModel?.userTriggeredSayHelloButton()
    }
}

MVVMExampleViewModel 은 간단한 ViewModel입니다.

class MVVMExampleViewModel {
    
    func userTriggeredSayHelloButton() {
        // How to update View's label when there is no reference to the View??
    }
}

보기에서 ViewModel의 참조를 설정하는 방법을 궁금해하실 것입니다. ViewController가 초기화 될 때 또는 표시되기 전에 일반적으로 수행합니다. 이 간단한 예제에서는 AppDelegate 에서 다음과 같은 작업을 수행합니다.

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        if let rootVC = window?.rootViewController as? MVVMExampleViewController {
            let viewModel = MVVMExampleViewModel()
            rootVC.viewModel = viewModel
        }
        
        return true

진짜 질문은 이제 ViewModel에 대한 뷰에 대한 참조를 제공하지 않고 ViewModel에서 View를 업데이트하는 방법입니다. (우리는 Reactive Programming iOS 라이브러리를 사용하지 않을 것임을 기억하십시오)

당신은 KVO를 사용하는 것에 대해 생각할 수 있습니다. 그러나 그것은 단지 많은 것을 복잡하게 만들 것입니다. 일부 영리한 사람들은이 문제에 대해 생각해 본드 도서관을 생각해 냈습니다. 처음에는 라이브러리가 복잡해 보일 수도 있고 조금 이해하기 어려울 수도 있으므로 여기서는 그 중 일부만 사용하고 MVVM을 완벽하게 사용할 것입니다.

간단하면서도 완전한 기능을 갖춘 MVVM 패턴의 핵심 인 Dynamic 클래스를 소개합시다.

class Dynamic<T> {
    typealias Listener = (T) -> Void
    var listener: Listener?
    
    func bind(_ listener: Listener?) {
        self.listener = listener
    }
    
    func bindAndFire(_ listener: Listener?) {
        self.listener = listener
        listener?(value)
    }
    
    var value: T {
        didSet {
            listener?(value)
        }
    }
    
    init(_ v: T) {
        value = v
    }
}

Dynamic 클래스는 Generics 및 Closure를 사용하여 ViewModel을 뷰와 바인딩합니다. 이 수업에 대한 자세한 내용은 다루지 않을 것입니다.이 예를 더 짧게하기 위해 주석에서 설명 할 수 있습니다. 이제 MVVMExampleViewControllerMVVMExampleViewModel 을 업데이트하여 해당 클래스를 사용하도록 MVVMExampleViewModel .

업데이트 된 MVVMExampleViewController

class MVVMExampleViewController: UIViewController {
    
    @IBOutlet weak var helloLabel: UILabel!
    
    var viewModel: MVVMExampleViewModel?
    
    override func viewDidLoad() {
        super.viewDidLoad()
        bindViewModel()
    }
    
    func bindViewModel() {
        if let viewModel = viewModel {
            viewModel.helloText.bind({ (helloText) in
                DispatchQueue.main.async {
                    // When value of the helloText Dynamic variable
                    // is set or changed in the ViewModel, this code will
                    // be executed
                    self.helloLabel.text = helloText
                }
            })
        }
    }
    
    @IBAction func sayHelloButtonPressed(_ sender: UIButton) {
        viewModel?.userTriggeredSayHelloButton()
    }
}

업데이트 된 MVVMExampleViewModel :

    class MVVMExampleViewModel {
    
    // we have to initialize the Dynamic var with the
    // data type we want
    var helloText = Dynamic("")
    
    func userTriggeredSayHelloButton() {
        // Setting the value of the Dynamic variable
        // will trigger the closure we defined in the View
        helloText.value = "Hello"
    }
}

그게 다야. 귀하 ViewModel 지금 업데이트 할 수있는 View 가에 대한 참조없이 View .

이것은 아주 간단한 예이지만 이것이 얼마나 강력한지를 알았을 것입니다. MVVM의 이점에 대해 자세히 설명하지는 않겠지 만 MVC에서 MVVM으로 전환하면 다시 돌아 가지 않습니다. 그냥 시도하고 직접보십시오.



Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow