खोज…
प्रतिक्रियाशील प्रोग्रामिंग के बिना MVVM
मैं वास्तव में एक छोटी व्याख्या के साथ शुरू करता हूँ कि आपके iOS ऐप में मॉडल-व्यू-व्यू -मॉडल (MVVM) डिज़ाइन पैटर्न का उपयोग क्यों और क्यों किया गया है। जब iOS पहली बार दिखाई दिया, तो Apple ने MVC (मॉडल-व्यू-कंट्रोलर) को एक डिज़ाइन पैटर्न के रूप में उपयोग करने का सुझाव दिया। उन्होंने इसे अपने सभी उदाहरणों में दिखाया और सभी पहले डेवलपर्स इसका उपयोग करके खुश थे क्योंकि यह व्यावसायिक तर्क और उपयोगकर्ता इंटरफ़ेस के बीच अच्छी तरह से अलग हो गए थे। जैसे-जैसे अनुप्रयोग बड़े और अधिक जटिल होते गए, एक नई समस्या उचित रूप से मैसिव व्यू कंट्रोलर्स (एमवीसी) के रूप में प्रकट हुई। क्योंकि व्यूकंट्रोलर में सभी व्यावसायिक तर्क जोड़े गए थे, समय के साथ वे आमतौर पर बहुत बड़े और जटिल हो गए थे। एमवीसी मुद्दे से बचने के लिए, आईओएस की दुनिया के लिए एक नया डिजाइन पैटर्न पेश किया गया था - मॉडल-व्यू-व्यूमॉडल (एमवीवीएम) पैटर्न।
ऊपर दिए गए आरेख से पता चलता है कि MVVM कैसा दिखता है। आपके पास एक मानक ViewController + View (स्टोरीबोर्ड, XIB या कोड में) है, जो MVVM के दृश्य के रूप में कार्य करता है (बाद के पाठ में - View MVVM के दृश्य का संदर्भ देगा)। एक दृश्य में एक ViewModel का संदर्भ होता है, जहां हमारा व्यावसायिक तर्क है। यह ध्यान रखना महत्वपूर्ण है कि ViewModel व्यू के बारे में कुछ नहीं जानता है और कभी भी व्यू का संदर्भ नहीं है। ViewModel में एक मॉडल का संदर्भ है।
यह MVVM के सैद्धांतिक भाग के साथ पर्याप्त है। इसके बारे में अधिक यहाँ पढ़ा जा सकता है ।
MVVM के साथ मुख्य मुद्दों में से एक यह है कि ViewModel के माध्यम से View को कैसे अपडेट किया जाए जब ViewModel का कोई संदर्भ नहीं है और View के बारे में कुछ भी नहीं जानता है।
इस उदाहरण का मुख्य भाग एमवीवीएम का उपयोग करना है (और अधिक सटीक रूप से, व्यूमॉडल और व्यू को कैसे बांधें) बिना किसी प्रतिक्रियात्मक प्रोग्रामिंग (रिएक्टिवकोआ, रिएक्टिवस्विफ्ट या आरएक्सविफ़) के उपयोग के लिए। एक नोट के रूप में: यदि आप रिएक्टिव प्रोग्रामिंग का उपयोग करना चाहते हैं, तो इससे भी बेहतर है कि एमवीवीएम बाइंडिंग का उपयोग करना वास्तव में आसान है। लेकिन यह उदाहरण रिएक्टिव प्रोग्रामिंग के बिना एमवीवीएम का उपयोग करने के तरीके पर है।
चलो एमवीवीएम का उपयोग करने के तरीके को प्रदर्शित करने के लिए एक सरल उदाहरण बनाते हैं।
हमारा MVVMExampleViewController
एक लेबल और एक बटन के साथ एक सरल ViewController है। जब बटन दबाया जाता है, तो लेबल पाठ को 'हैलो' पर सेट किया जाना चाहिए। उपयोगकर्ता उपयोगकर्ता इंटरैक्शन पर क्या करना है यह तय करने के बाद से, व्यापार तर्क का हिस्सा है, 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 से View को अपडेट कैसे करें, ViewModel का संदर्भ दिए बिना? (याद रखें, हम किसी भी रिएक्टिव प्रोग्रामिंग आईओएस लाइब्रेरी का उपयोग नहीं करेंगे)
आप केवीओ का उपयोग करने के बारे में सोच सकते हैं, लेकिन यह सिर्फ चीजों को बहुत अधिक जटिल करेगा। कुछ स्मार्ट लोगों ने इस मुद्दे के बारे में सोचा और बॉन्ड लाइब्रेरी के साथ आए। पुस्तकालय जटिल लग सकता है और पहली बार में समझना थोड़ा कठिन हो सकता है, इसलिए मैं सिर्फ इसका एक छोटा हिस्सा ले लूंगा और हमारे MVVM को पूरी तरह कार्यात्मक बना दूंगा।
आइए Dynamic
क्लास का परिचय देते हैं जो हमारे सरल लेकिन पूरी तरह कार्यात्मक MVVM पैटर्न का मूल है।
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
क्लास हमारे ViewModel को हमारे View से बाँधने के लिए Generics और Closures का उपयोग कर रहा है। मैं इस वर्ग के बारे में विवरण में नहीं जाऊंगा, हम इसे टिप्पणियों में कर सकते हैं (इस उदाहरण को छोटा करने के लिए)। आइए अब उन वर्गों का उपयोग करने के लिए हमारे MVVMExampleViewController
और 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 पर स्विच करते हैं, तो आप वापस नहीं जाएंगे। बस इसे आज़माएं और अपने लिए देखें।