IOS ऐप्स में एप्लिकेशन समन्वयक

हर साल, iOS प्लेटफ़ॉर्म कई बदलावों से गुजरता है, इसके अलावा, थर्ड-पार्टी लाइब्रेरी नियमित रूप से नेटवर्क के साथ काम करने, डेटा कैशिंग, जावास्क्रिप्ट के माध्यम से यूआई प्रदान करने आदि पर काम करती है। इन सभी रुझानों के विपरीत, पावेल गुरोव ने वास्तु समाधान के बारे में बात की, जो इस बात पर ध्यान दिए बिना होगा कि आप अभी किन तकनीकों का उपयोग कर रहे हैं या कुछ वर्षों में उपयोग कर रहे हैं।

ApplicationCoordinator का उपयोग स्क्रीन के बीच नेविगेशन बनाने के लिए किया जा सकता है, और एक ही समय में कई समस्याओं का समाधान किया जा सकता है। बिल्ली डेमो के तहत और इस दृष्टिकोण के सबसे तेजी से कार्यान्वयन के लिए निर्देश।



स्पीकर के बारे में: पावेल गुरोव अवितो में आईओएस एप्लिकेशन विकसित कर रहा है।



नेविगेशन





स्क्रीन के बीच नेविगेट करना एक ऐसा कार्य है जिसका 100% आप के साथ सामना किया जाता है, इससे कोई फर्क नहीं पड़ता कि आप क्या करते हैं - एक सामाजिक नेटवर्क, एक टैक्सी कॉल या एक ऑनलाइन बैंक। प्रोटोटाइप स्टेज पर भी यही शुरू होता है, जब आप पूरी तरह से यह भी नहीं जानते हैं कि स्क्रीन कैसी दिखेगी, तो वे किस तरह के एनिमेशन देखेंगे, क्या डेटा कैश होगा। स्क्रीन रिक्त या स्थिर चित्र हो सकते हैं, लेकिन जैसे ही इनमें से एक से अधिक स्क्रीन हैं, नेविगेशन कार्य अनुप्रयोग में दिखाई देता है । यानी लगभग तुरंत।



आईओएस अनुप्रयोगों के आर्किटेक्चर के निर्माण के लिए सबसे सामान्य तरीके: एमवीसी, एमवीवीएम और एमवीपी, एकल स्क्रीन मॉड्यूल का निर्माण करने का तरीका बताते हैं। यह भी कहता है कि मॉड्यूल एक दूसरे के बारे में जान सकते हैं, एक दूसरे के साथ संवाद कर सकते हैं, आदि। लेकिन इस बात पर बहुत कम ध्यान दिया जाता है कि इन मॉड्यूलों के बीच संक्रमण कैसे होता है, इन बदलावों का निर्णय कौन करता है और डेटा कैसे प्रसारित होता है।

UlStoryboard + सेगमेंट


बॉक्स से बाहर iOS निम्नलिखित स्क्रीन परिदृश्य को दिखाने के कई तरीके प्रदान करता है:

  1. जब हम एक मेटा-फ़ाइल में स्क्रीन के बीच सभी बदलावों को नामित करते हैं, और तब उन्हें कॉल करते हैं, तो प्रसिद्ध UlStoryboard + का तर्क है। सब कुछ बहुत सुविधाजनक और महान है।
  2. कंटेनर - जैसे कि UINavigationController। UITabBarController, UIPageController या, संभवतः, स्व-लिखित कंटेनर जिन्हें प्रोग्रामेटिक रूप से और StoryBoards के साथ एक साथ उपयोग किया जा सकता है।
  3. विधि मौजूद (_: एनिमेटेड: पूरा होने :)। यह सिर्फ UIController क्लास का एक तरीका है।

इन उपकरणों के साथ कोई समस्या नहीं है। समस्या वास्तव में यह है कि वे आमतौर पर कैसे उपयोग किए जाते हैं। UinavigationController, PerformSegue, readyForSegue, presentViewController विधि सभी UIViewController क्लास की संपत्ति गुण हैं। Apple UIViewController के अंदर इन उपकरणों का उपयोग करने का सुझाव देता है।



इसका प्रमाण निम्नलिखित है।



यदि आप एक मानक टेम्पलेट का उपयोग करके UIViewController का एक नया उपवर्ग बनाते हैं तो यह आपकी परियोजना में दिखाई देने वाली टिप्पणियाँ हैं। यह सीधे लिखा जाता है - यदि आप सेग्यू का उपयोग करते हैं और आपको परिदृश्य के अनुसार अगली स्क्रीन पर डेटा स्थानांतरित करने की आवश्यकता है, तो आपको यह करना चाहिए: इस ViewController को segue से प्राप्त करें; पता है कि यह किस प्रकार का होगा; इसे इस प्रकार पर कास्ट करें और वहां अपना डेटा पास करें।

नेविगेशन के निर्माण में समस्याओं के लिए यह दृष्टिकोण।

1. स्क्रीन की कठोर कनेक्टिविटी

इसका मतलब यह है कि स्क्रीन 1 स्क्रीन के अस्तित्व के बारे में जानता है। न केवल वह अपने अस्तित्व के बारे में जानता है, यह संभावित रूप से इसे भी बनाता है, या इसे सेग्यू से लेता है, यह जानते हुए कि यह किस प्रकार का है, और इसके लिए कुछ डेटा स्थानांतरित करता है।

अगर हमें कुछ परिस्थितियों में, स्क्रीन 2 के बजाय स्क्रीन 3 को प्रदर्शित करने की आवश्यकता है, तो हमें नई स्क्रीन 3 के बारे में उसी तरह से जानना होगा, जैसे स्क्रीन नियंत्रक में सिले होना 1. सब कुछ और भी मुश्किल हो जाता है यदि नियंत्रकों 2 और 3 को कई स्थानों से बुलाया जा सकता है, न केवल स्क्रीन 1 से। यह पता चलता है कि स्क्रीन 2 और 3 के ज्ञान को इनमें से प्रत्येक स्थान पर सिलना होगा।

ऐसा करने के लिए परेशानी का एक और आधा हिस्सा है, मुख्य समस्याएं तब शुरू होंगी जब इन बदलावों में बदलाव करना आवश्यक है, या इन सभी का समर्थन करना है।



2. स्क्रिप्ट स्क्रिप्ट कंट्रोलर

यह भी कनेक्शन की वजह से इतना सरल नहीं है। दो ViewControllers स्वैप करने के लिए, यह UlStoryboard में जाने और 2 चित्रों को स्वैप करने के लिए पर्याप्त नहीं होगा। आपको इनमें से प्रत्येक स्क्रीन के लिए कोड खोलना होगा, इसे अगले एक की सेटिंग्स में स्थानांतरित करना होगा, और इसके स्थानों को बदलना होगा, जो बहुत सुविधाजनक नहीं है।



3. परिदृश्य के अनुसार डेटा स्थानांतरण

उदाहरण के लिए, स्क्रीन 3 पर कुछ चुनते समय, हमें स्क्रीन पर व्यू को अपडेट करने की आवश्यकता होती है। 1. चूंकि हमारे पास शुरू में ViewController के अलावा कुछ भी नहीं है, इसलिए हमें किसी तरह से दो ViewControllers को कनेक्ट करना होगा - इससे कोई फर्क नहीं पड़ता कि प्रतिनिधि के माध्यम से - या किसी तरह अभी तक। यह और भी मुश्किल होगा यदि, स्क्रीन 3 पर कार्रवाई के अनुसार, एक स्क्रीन को अपडेट करना आवश्यक नहीं होगा, लेकिन एक बार में कई, उदाहरण के लिए, पहला और दूसरा।



इस मामले में, प्रतिनिधिमंडल के साथ विवाद नहीं किया जा सकता है, क्योंकि प्रतिनिधिमंडल एक-से-एक संबंध है। कोई कहेगा, चलो अधिसूचना का उपयोग करें, कोई - एक साझा राज्य के माध्यम से। यह सब हमारे आवेदन में डेटा प्रवाह को डीबग और ट्रैक करना मुश्किल बनाता है।

जैसा कि वे कहते हैं, 100 बार सुनने की तुलना में एक बार देखना बेहतर है। आइए इस Avito Services Pro एप्लिकेशन से एक विशिष्ट उदाहरण देखें। यह एप्लिकेशन सेवा क्षेत्र के पेशेवरों के लिए है, जिसमें आपके आदेशों को ट्रैक करना, ग्राहकों के साथ संवाद करना, नए आदेशों की तलाश करना सुविधाजनक है।

परिदृश्य - उपयोगकर्ता प्रोफ़ाइल के संपादन में एक शहर चुनना।



यहां एक प्रोफ़ाइल संपादन स्क्रीन है, जैसे कई अनुप्रयोगों में है। हम एक शहर चुनने में रुचि रखते हैं।

यहाँ क्या हो रहा है?

  • उपयोगकर्ता शहर के साथ सेल पर क्लिक करता है, और पहली स्क्रीन तय करती है कि नेविगेशन स्टैक में निम्न स्क्रीन को जोड़ने का समय है। यह संघीय शहरों की सूची (मॉस्को और सेंट पीटर्सबर्ग) और क्षेत्रों की सूची के साथ एक स्क्रीन है।
  • यदि उपयोगकर्ता दूसरी स्क्रीन पर एक संघीय शहर का चयन करता है, तो दूसरी स्क्रीन यह समझती है कि स्क्रिप्ट पूरी हो गई है, पहले चयनित शहर को आगे और नेविगेशन स्टैक को पहली स्क्रीन पर वापस रोल करता है। स्क्रिप्ट पूरी मानी जाती है।
  • यदि उपयोगकर्ता दूसरी स्क्रीन पर एक क्षेत्र का चयन करता है, तो दूसरी स्क्रीन तय करती है कि तीसरी स्क्रीन को तैयार करने की आवश्यकता है, जिसमें हम इस क्षेत्र के शहरों की सूची देखते हैं। यदि उपयोगकर्ता किसी शहर का चयन करता है, तो यह शहर पहली स्क्रीन पर भेजा जाता है, नेविगेशन स्टैक को रोल करता है और स्क्रिप्ट को पूर्ण माना जाता है।

इस चित्र में, मेरे द्वारा पहले बताई गई कनेक्टिविटी समस्याओं को ViewController के बीच तीर के रूप में दिखाया गया है। हम अब इन समस्याओं से छुटकारा पा लेंगे।

हम यह कैसे करते हैं?

  1. हम स्वयं को UIViewController के अंदर कंटेनरों का उपयोग करने के लिए मना करते हैं , अर्थात, self.navigationController, self.tabBarController या कुछ अन्य कस्टम कंटेनरों के लिए जिसे आपने संपत्ति विस्तार के रूप में बनाया था। अब हम अपने कंटेनर को स्क्रीन कोड से नहीं ले सकते हैं और इसे कुछ करने के लिए कह सकते हैं।


  2. हम खुद को UIViewController के अंदर करने के लिए मना करते हैं PerformSegue विधि को कॉल करने और तैयार करने के लिए CodeForSegue विधि में कोड लिखें, जो स्क्रिप्ट का अनुसरण करने वाली स्क्रीन को ले जाएगा और इसे कॉन्फ़िगर करेगा। यही है, अब हम UIViewController के अंदर सेगमेंट (स्क्रीन के बीच संक्रमण के साथ) के साथ काम नहीं करते हैं।


  3. हम अपने विशिष्ट नियंत्रक के अंदर अन्य नियंत्रकों के किसी भी उल्लेख पर रोक लगाते हैं : कोई आरंभीकरण, डेटा स्थानांतरण, और यह सब नहीं है।




समन्वयक


चूंकि हम इन सभी जिम्मेदारियों को UIViewController से हटाते हैं, हमें एक नई इकाई की आवश्यकता होती है जो उन्हें निष्पादित करेगी। वस्तुओं का एक नया वर्ग बनाएं, और इसे समन्वयक कहें।



समन्वयक केवल एक सामान्य वस्तु है, जिसके लिए हम नेवीगेशनकंट्रोलर की शुरुआत में गुजरते हैं और स्टार्ट विधि को कॉल करते हैं। अब इस बारे में न सोचें कि इसे कैसे लागू किया जाता है, बस यह देखें कि इस मामले में शहर चुनने का परिदृश्य कैसे बदल जाएगा।

अब यह इस तथ्य के साथ शुरू नहीं होता है कि हम किसी भी विशिष्ट नेविगेशनकंट्रोलर स्क्रीन पर संक्रमण की तैयारी कर रहे हैं, लेकिन हम कोऑर्डिनेटर में स्टार्ट विधि को कहते हैं, इससे पहले इसे नेविगेशनकोंट्रोलर इनिशियलाइज़र में पास कर दें। समन्वयक समझता है कि यह नेविगेशनकंट्रोलर के लिए पहली स्क्रीन लॉन्च करने का समय है, जो वह करता है।

इसके अलावा, जब उपयोगकर्ता किसी शहर के साथ एक सेल का चयन करता है, तो यह ईवेंट समन्वयक तक पहुंच जाता है। यही है, स्क्रीन को खुद कुछ भी नहीं पता है - इसके बाद, जैसा कि वे कहते हैं, कम से कम बाढ़। वह इस संदेश को समन्वयक को भेजता है, और फिर समन्वयक इसके द्वारा प्रतिक्रिया करता है (क्योंकि उसके पास एक नेविगेशनकंट्रोलर है), जो इसे अगला चरण भेजता है - यह क्षेत्रों का विकल्प है।

अगला, उपयोगकर्ता "क्षेत्र" पर क्लिक करता है - ठीक उसी तस्वीर - स्क्रीन स्वयं कुछ भी हल नहीं करती है, केवल समन्वयक को बताती है कि अगली स्क्रीन खुलती है।

जब उपयोगकर्ता तीसरी स्क्रीन पर एक विशिष्ट शहर का चयन करता है, तो यह शहर समन्वयक के माध्यम से पहली स्क्रीन पर भी स्थानांतरित किया जाता है। अर्थात्, समन्वयक को एक संदेश भेजा जाता है कि एक शहर का चयन किया गया है। समन्वयक इस संदेश को पहली स्क्रीन पर भेजता है और पहली स्क्रीन पर नेविगेशन स्टैक को रोल करता है।

ध्यान दें कि नियंत्रक अब एक-दूसरे के साथ संवाद नहीं करते हैं , यह तय करते हैं कि अगला कौन होगा, और एक-दूसरे को कोई डेटा संचारित नहीं करेगा। इसके अलावा, वे अपने आसपास के बारे में कुछ भी नहीं जानते हैं।



यदि हम एक तीन-परत वास्तुकला के ढांचे के भीतर आवेदन पर विचार करते हैं, तो ViewController को आदर्श रूप से प्रस्तुति परत में पूरी तरह से फिट होना चाहिए और आवेदन तर्क को जितना संभव हो उतना कम ले जाना चाहिए।

इस मामले में, हम कोऑर्डिनेटर का उपयोग ऊपर की परत के लिए संक्रमण के तर्क को बाहर निकालने के लिए करते हैं और ViewController से इस ज्ञान को हटाते हैं।

डेमो


एक प्रस्तुति और डेमो प्रोजेक्ट गितुब पर उपलब्ध है, नीचे बात के दौरान एक प्रदर्शन है।


यह वही परिदृश्य है: किसी प्रोफ़ाइल को संपादित करना और उसमें एक शहर चुनना।

पहली स्क्रीन यूजर एडिट स्क्रीन है। यह वर्तमान उपयोगकर्ता: नाम और चयनित शहर के बारे में जानकारी दिखाता है। एक बटन है "एक शहर चुनें।" जब हम उस पर क्लिक करते हैं, तो हम शहरों की सूची के साथ स्क्रीन पर आते हैं। अगर हम वहां एक शहर का चयन करते हैं, तो पहली स्क्रीन इस शहर को मिलती है।

अब देखते हैं कि यह कोड में कैसे काम करता है। चलो मॉडल के साथ शुरू करते हैं।

struct City { let name: String } struct User { let name: String var city: City? } 

मॉडल सरल हैं:

  1. एक शहर की संरचना जिसमें एक फ़ील्ड नाम, स्ट्रिंग है;
  2. एक उपयोगकर्ता जिसका एक नाम और संपत्ति शहर भी है।

इसके बाद की कहानी स्टोरीबोर्ड है । यह एक नेविगेशनकंट्रोलर के साथ शुरू होता है। सिद्धांत रूप में, यहां वही स्क्रीन हैं जो सिम्युलेटर में थे: एक लेबल के साथ एक उपयोगकर्ता संपादन स्क्रीन और एक बटन और शहरों की सूची के साथ एक स्क्रीन, जो शहरों के साथ एक टैबलेट दिखाता है।

उपयोगकर्ता संपादित स्क्रीन


 import UIKit final class UserEditViewController: UIViewController, UpdateableWithUser { // MARK: - Input - var user: User? { didSet { updateView() } } // MARK: - Output - var onSelectCity: (() -> Void)? @IBOutlet private weak var userLabel: UILabel? @IBAction private func selectCityTap(_ sender: UIButton) { onSelectCity?() } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) updateView() } private func updateView() { userLabel?.text = "User: \(user?.name ?? ""), \n" + "City: \(user?.city?.name ?? "")" } } 

यहां एक संपत्ति उपयोगकर्ता है - यह वह उपयोगकर्ता है जिसे बाहर प्रसारित किया जाता है - वह उपयोगकर्ता जिसे हम संपादित करेंगे। यहां उपयोगकर्ता सेट करें, डिडसेट ब्लॉक को कॉल करने का कारण बनता है, जो स्थानीय अपडेट व्यू () विधि के लिए कॉल करता है। यह सब विधि जो करता है, वह केवल लेबल पर उपयोगकर्ता के बारे में जानकारी रखता है, अर्थात्, उसका नाम और उस शहर का नाम दिखाता है जिसमें उपयोगकर्ता रहता है।

एक ही बात viewWillAppear () विधि में होती है।

सबसे दिलचस्प जगह शहर के चयन बटन पर क्लिक करने के लिए हैंडलर हैसिटीटैप ()। यहां नियंत्रक स्वयं कुछ भी हल नहीं करता है : यह कोई नियंत्रक नहीं बनाता है, यह किसी भी सेगमेंट को नहीं बुलाता है। वह जो कुछ भी करता है वह कॉलबैक है - यह हमारे ViewController की दूसरी संपत्ति है। OnSelectCity कॉलबैक में कोई पैरामीटर नहीं है। जब उपयोगकर्ता बटन पर क्लिक करता है, तो यह कॉलबैक कहलाता है।

शहर चयन स्क्रीन


 import UIKit final class CitiesViewController: UITableViewController { // MARK: - Output - var onCitySelected: ((City) -> Void)? // MARK: - Private variables - private let cities: [City] = [City(name: "Moscow"), City(name: "Ulyanovsk"), City(name: "New York"), City(name: "Tokyo")] // MARK: - Table - override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return cities.count } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) cell.textLabel?.text = cities[indexPath.row].name return cell } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { onCitySelected?(cities[indexPath.row]) } } 

यह स्क्रीन एक UITableViewController है। यहां शहरों की सूची तय है, लेकिन यह कहीं और से आ सकती है। इसके अलावा (// MARK: - टेबल -) एक काफी तुच्छ टेबल कोड है जो कोशिकाओं में शहरों की सूची प्रदर्शित करता है।

यहां सबसे दिलचस्प जगह है, सब-रे-इंडेक्सपैथ हैंडलर, जो सभी के लिए एक प्रसिद्ध तरीका है। यहां स्क्रीन फिर से कुछ भी हल नहीं करता है। शहर के चयन के बाद क्या होता है? यह केवल एक एकल पैरामीटर "शहर" के साथ कॉलबैक कहता है।

यह स्क्रीन के लिए कोड को स्वयं समाप्त करता है। जैसा कि हम देखते हैं, वे अपने पर्यावरण के बारे में कुछ भी नहीं जानते हैं।

समन्वयक


आइए इन स्क्रीन के बीच की कड़ी पर चलते हैं।

 import UIKit protocol UpdateableWithUser: class { var user: User? { get set } } final class UserEditCoordinator { // MARK: - Properties private var user: User { didSet { updateInterfaces() } } private weak var navigationController: UINavigationController? // MARK: - Init init(user: User, navigationController: UINavigationController) { self.user = user self.navigationController = navigationController } func start() { showUserEditScreen() } // MARK: - Private implementation private func showUserEditScreen() { let controller = UIStoryboard.makeUserEditController() controller.user = user controller.onSelectCity = { [weak self] in self?.showCitiesScreen() } navigationController?.pushViewController(controller, animated: false) } private func showCitiesScreen() { let controller = UIStoryboard.makeCitiesController() controller.onCitySelected = { [weak self] city in self?.user.city = city _ = self?.navigationController?.popViewController(animated: true) } navigationController?.pushViewController(controller, animated: true) } private func updateInterfaces() { navigationController?.viewControllers.forEach { ($0 as? UpdateableWithUser)?.user = user } } } 

समन्वयक के दो गुण हैं:

  1. उपयोगकर्ता - उपयोगकर्ता जिसे हम संपादित करेंगे;
  2. नेविगेशनकंट्रोलर जो स्टार्टअप पर पारित करने के लिए।

एक साधारण इनिट () है जो इन संपत्ति को आबाद करती है।

अगला प्रारंभ () विधि है, जो ShowUserEditScreen () विधि को कहा जाता है । आइए हम इस पर अधिक विस्तार से ध्यान दें। यह विधि नियंत्रक को UIStoryboard से बाहर ले जाती है, इसे हमारे स्थानीय उपयोगकर्ता को भेजती है। फिर वह onSelectCity कॉलबैक डालता है और इस कंट्रोलर को नेविगेशन स्टैक में धकेल देता है।

उपयोगकर्ता बटन पर क्लिक करने के बाद, ऑनसिटी कॉलबैक चालू हो जाता है, और यह निम्नलिखित निजी ShowCitiesScreen () विधि का कारण बनता है।

वास्तव में, यह लगभग एक ही काम करता है - यह UIStoryboard से थोड़ा अलग नियंत्रक को उठाता है, इस पर onCitySelected कॉलबैक डालता है और इसे नेविगेशन स्टैक में धकेलता है - यह सब होता है। जब उपयोगकर्ता किसी विशिष्ट शहर का चयन करता है, तो यह कॉलबैक चालू हो जाता है, समन्वयक हमारे स्थानीय उपयोगकर्ता के "शहर" क्षेत्र को अपडेट करता है और पहली स्क्रीन पर नेविगेशन स्टैक रोल करता है।

चूंकि उपयोगकर्ता एक संरचना है, इसलिए फ़ील्ड "शहर" को अपडेट करने से यह इस तथ्य की ओर जाता है कि डिडसेट ब्लॉक को क्रमशः, निजी विधि अपडेटइंटरफेस () कहा जाता है। यह विधि संपूर्ण नेविगेशन स्टैक से होकर गुजरती है और प्रत्येक ViewController को UpdateateableWithUser प्रोटोकॉल के रूप में तैनात करने का प्रयास करती है। यह सबसे सरल प्रोटोकॉल है, जिसमें केवल एक संपत्ति है - उपयोगकर्ता। यदि यह सफल होता है, तो वह इसे अपडेट किए गए उपयोगकर्ता के पास फेंक देता है। इस प्रकार, यह पता चला है कि दूसरी स्क्रीन पर हमारा चयनित उपयोगकर्ता स्वचालित रूप से पहली स्क्रीन पर कूदता है।

समन्वयक के साथ सब कुछ स्पष्ट है, और यहां दिखाने के लिए केवल एक चीज बची है जो हमारे आवेदन का प्रवेश बिंदु है। यह वह जगह है जहाँ यह सब शुरू होता है। इस मामले में, यह हमारे AppDelegate का DidFinishLaunchingWithOptions विधि है।

 import UIKit @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? var coordinator: UserEditCoordinator! func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { guard let navigationController = window?.rootViewController as? UINavigationController else { return true } let user = User(name: "Pavel Gurov", city: City(name: "Moscow")) coordinator = UserEditCoordinator(user: user, navigationController: navigationController) coordinator.start() return true } } 

यहां नेविगेशनकंट्रोलर को UIStoryboard से लिया गया है, एक उपयोगकर्ता बनाया गया है, जिसे हम एक नाम और एक विशिष्ट शहर के साथ संपादित करेंगे। अगला हम उपयोगकर्ता और नेवीगेशन कंट्रोलर के साथ अपना समन्वयक बनाते हैं। इसे स्टार्ट () विधि कहते हैं। समन्वयक को स्थानीय संपत्ति में स्थानांतरित किया जाता है - यह मूल रूप से सभी है। योजना काफी सरल है।

इनपुट्स और आउटपुट


ऐसे कई बिंदु हैं जिन पर मैं अधिक विस्तार से ध्यान देना चाहूंगा। आपने शायद देखा कि userEditViewController में संपत्ति को इनपुट के रूप में एक टिप्पणी के साथ चिह्नित किया गया है, और इन नियंत्रकों के कॉलबैक को आउटपुट के रूप में चिह्नित किया गया है।



एक इनपुट कोई भी डेटा है जो समय के साथ बदल सकता है, साथ ही कुछ ViewController तरीके जो बाहर से बुलाए जा सकते हैं। उदाहरण के लिए, UserEditViewController में यह एक उपयोगकर्ता संपत्ति है - उपयोगकर्ता स्वयं या इसके सिटी पैरामीटर बदल सकते हैं।

बाहर निकलने की कोई भी घटना है जो नियंत्रक बाहरी दुनिया से संवाद करना चाहता है। UserEditViewController में, यह onSelectCity बटन पर एक क्लिक है, और शहर के चयन स्क्रीन पर, यह एक विशिष्ट शहर के साथ एक सेल पर एक क्लिक है। यहां मुख्य विचार है, मैं दोहराता हूं, कि नियंत्रक को कुछ भी नहीं पता है और इन घटनाओं के बारे में कुछ भी नहीं करता है। वह तय करता है कि किसी और को क्या करना है।

ऑब्जेक्टिव-सी में, मुझे वास्तव में उनके भयानक सिंटैक्स के कारण कॉलबैक सहेजना लिखना पसंद नहीं था। लेकिन स्विफ्ट में, यह बहुत सरल है। इस मामले में कॉलबैक का उपयोग करना iOS में प्रसिद्ध प्रतिनिधिमंडल पैटर्न का एक विकल्प है। केवल यहां, प्रोटोकॉल में तरीकों को नामित करने के बजाय और यह कहते हुए कि समन्वयक इस प्रोटोकॉल से मेल खाता है, और फिर इन विधियों को अलग से लिख रहा है, हम तुरंत एक जगह में बहुत आसानी से एक इकाई बना सकते हैं, इसे कॉलबैक डाल सकते हैं और यह सब कर सकते हैं।

सच है, इस दृष्टिकोण के साथ, प्रतिनिधिमंडल के विपरीत, समन्वयक और स्क्रीन के सार के बीच एक तंग संबंध है, क्योंकि समन्वयक जानता है कि स्क्रीन का एक विशिष्ट सार है।

आप प्रोटोकॉल का उपयोग करके प्रतिनिधिमंडल की तरह ही इससे छुटकारा पा सकते हैं।



कनेक्टिविटी से बचने के लिए, हम प्रोटोकॉल के साथ अपने कंट्रोलर के इनपुट और आउटपुट को बंद कर सकते हैं।

ऊपर शहरओटपुट प्रोटोकॉल है, जिसकी बिल्कुल एक आवश्यकता है - ऑनसिटी सेलेक्टेड कॉलबैक। बाईं ओर स्विफ्ट पर इस योजना का एक एनालॉग है। हमारे नियंत्रक इस प्रोटोकॉल का अनुपालन करते हैं, आवश्यक कॉलबैक का निर्धारण करते हैं। हम ऐसा इसलिए करते हैं ताकि समन्वयक को सिटीज व्यू कॉन्ट्रोलर वर्ग के अस्तित्व के बारे में पता न चले। लेकिन कुछ बिंदु पर उसे इस नियंत्रक के आउटपुट को कॉन्फ़िगर करने की आवश्यकता होगी। इसे पूरी तरह से क्रैंक करने के लिए, हम एक फैक्ट्री कोऑर्डिनेटर से जोड़ते हैं।



कारखाने में एक सिटीऑटपुट () विधि है। यह पता चला है कि हमारा समन्वयक एक नियंत्रक नहीं बनाता है और इसे कहीं से नहीं मिलता है। एक कारखाना उस पर फेंकता है, जो विधि द्वारा प्रोटोकॉल में बंद की गई वस्तु को लौटाता है, और उसे इस बात का कुछ भी पता नहीं होता है कि यह वस्तु किस वर्ग की है।

अब सबसे महत्वपूर्ण बात - यह सब क्यों करते हैं? जब हमें कोई समस्या नहीं थी तो हमें एक और अतिरिक्त स्तर पर निर्माण करने की आवश्यकता क्यों है?

कोई भी इस स्थिति की कल्पना कर सकता है: एक प्रबंधक हमारे पास आएगा और आपको ए / बी इस तथ्य का परीक्षण करने के लिए कहेगा कि शहरों की सूची के बजाय हमारे पास नक्शे पर एक शहर का विकल्प होगा। यदि हमारे आवेदन में शहर की पसंद एक जगह नहीं होती, लेकिन विभिन्न संयोजकों में, अलग-अलग परिदृश्यों में, हमें प्रत्येक स्थान पर एक झंडे को सीना होता था, उसे बाहर टॉस करना होता था, इस झंडे में से एक या दूसरे व्यू कॉन्ट्रोलर को उठाते थे। यह बहुत सुविधाजनक नहीं है।

हम इस ज्ञान को समन्वयक से दूर करना चाहते हैं। इसलिए, कोई एक जगह ऐसा कर सकता है। कारखाने में ही, हम एक पैरामीटर बनाते हैं जिसके द्वारा कारखाने प्रोटोकॉल द्वारा बंद किए गए एक या दूसरे नियंत्रक को वापस कर देते हैं। उन दोनों के पास एक कॉलबैक होगाइंटरसेलेक्टेड, और समन्वयक, सिद्धांत रूप में, परवाह नहीं करेगा कि इनमें से कौन सी स्क्रीन के साथ काम करना है - एक नक्शा या एक सूची।

रचना वी.एस.


अगला बिंदु जिस पर मैं वास करना चाहता था वह विरासत के विरुद्ध रचना है।



  1. पहली विधि यह है कि हमारा समन्वयक कैसे किया जा सकता है, जब यह नेविगेशनकंट्रोलर को बाहर से पारित किया जाता है और स्थानीय रूप से संपत्ति के रूप में संग्रहीत किया जाता है , तो रचना को बनाना है । यह एक रचना की तरह है - हमने इसमें एक संपत्ति के रूप में एक नेविगेशनकंट्रोलर जोड़ा।
  2. दूसरी ओर, एक राय है कि यूआई किट में सब कुछ है, और हमें पहिया को सुदृढ़ करने की आवश्यकता नहीं है। आप बस UI नेवीगेशनकंट्रोलर को ले और विरासत में ले सकते हैं।

प्रत्येक विकल्प के पास इसके पेशेवरों और विपक्ष हैं, लेकिन व्यक्तिगत रूप से यह मुझे लगता है कि इस मामले में रचना विरासत से अधिक उपयुक्त है। वंशानुक्रम आम तौर पर एक कम लचीली योजना है। यदि हमें उदाहरण के लिए, UIPageController को नेविगेशन बदलने के लिए, उदाहरण के लिए, जरूरत है, तो पहले मामले में हम उन्हें केवल एक सामान्य प्रोटोकॉल के साथ बंद कर सकते हैं, जैसे कि "अगली स्क्रीन दिखाएं" और आसानी से कंटेनर की जरूरत है।

मेरे दृष्टिकोण से, सबसे महत्वपूर्ण तर्क यह है कि आप रचना में अंत उपयोगकर्ता से सभी अनावश्यक तरीकों को छिपाते हैं। यह पता चला है कि वह ठोकर की संभावना कम है। आप केवल उन्हीं API को छोड़ते हैं जिनकी आवश्यकता है , उदाहरण के लिए, प्रारंभ विधि - और वह सब। उसके पास PushViewController, PopViewController विधि को कॉल करने का कोई तरीका नहीं है, अर्थात्, किसी भी तरह समन्वयक की गतिविधियों में हस्तक्षेप करता है। मूल वर्ग के सभी तरीके छिपे हुए हैं।

स्टोरीबोर्ड


मेरा मानना ​​है कि वे बहस के साथ-साथ विशेष ध्यान देने योग्य हैं। व्यक्तिगत रूप से, मैं सेगमेंट का समर्थन करता हूं , क्योंकि वे आपको स्क्रिप्ट के साथ खुद को जल्दी से परिचित करने की अनुमति देते हैं। जब कोई नया डेवलपर आता है, तो उसे कोड पर चढ़ने की आवश्यकता नहीं होती है, स्टोरीबोर्ड इसकी मदद करता है। यहां तक ​​कि अगर आप कोड के साथ एक इंटरफ़ेस बनाते हैं, तो आप खाली ViewController छोड़ सकते हैं, और कोड के साथ इंटरफ़ेस बना सकते हैं, लेकिन कम से कम संक्रमण और पूरे बिंदु को छोड़ सकते हैं। स्टोरीबोर्ड का पूरा सार स्वयं बदलावों में है, न कि UI के लेआउट में।

सौभाग्य से, समन्वयक दृष्टिकोण उपकरण की पसंद को सीमित नहीं करता है । हम सुरक्षित रूप से समन्वयकों के साथ समन्वयकों का उपयोग कर सकते हैं। लेकिन हमें याद रखना चाहिए कि अब हम UIViewController के अंदर सेगमेंट के साथ काम नहीं कर सकते हैं।



इसलिए, हमें अपनी कक्षा में onPrepareForSegue विधि को ओवरराइड करना चाहिए। नियंत्रक के अंदर कुछ करने के बजाय, हम कॉलबैक के माध्यम से इन कार्यों को फिर से समन्वयक को सौंप देंगे। OnPrepareForSegue विधि को कहा जाता है, आप स्वयं कुछ भी नहीं करते हैं - आप यह नहीं जानते कि यह किस प्रकार का तर्क है, यह किस गंतव्य नियंत्रक का है - यह आपके लिए महत्वपूर्ण नहीं है। आप बस एक कॉलबैक में इसे फेंक देंगे, और समन्वयक यह पता लगाएगा। उसके पास यह ज्ञान है, आपको इस ज्ञान की आवश्यकता नहीं है।

सब कुछ सरल बनाने के लिए, आप इसे एक निश्चित बेस क्लास में कर सकते हैं ताकि अलग से लिए गए प्रत्येक कंट्रोलर में इसे ओवरराइड न करें। इस मामले में, समन्वयक के लिए अपने सेगमेंट के साथ काम करना अधिक सुविधाजनक होगा।

एक और बात जो मुझे स्टोरीबोर्ड के साथ सुविधाजनक लगती है, वह है नियम का पालन करना कि एक स्टोरीबोर्ड एक समन्वयक के बराबर है । फिर आप सब कुछ बहुत सरल कर सकते हैं, सामान्य रूप से एक वर्ग बना सकते हैं - स्टोरीबोर्डकॉर्डिनेटर, और इसमें रूटटेप पैरामीटर उत्पन्न करें, स्टोरीबोर्ड में प्रारंभिक नेविगेशन नियंत्रक बनाएं और इसमें पूरी स्क्रिप्ट लपेटें।



जैसा कि आप देख सकते हैं, यहां समन्वयक के पास 2 संपत्ति है: नेविगेशनकंट्रोलर; हमारे रूट टाइप का रूट व्यू कंट्रोलर जेनेरिक है। आरंभीकरण के दौरान, हम इसके लिए एक विशिष्ट नेविगेशनकंट्रोलर नहीं, बल्कि एक स्टोरीबोर्ड से गुजरते हैं, जहाँ से हमारा रूट नेविगेशन और इसका पहला नियंत्रक मिलता है। इस तरह से हमें किसी भी तरीके से कॉल नहीं करना है। यही है, आपने एक समन्वयक बनाया, उसके पास तुरंत नेविगेशन है, और तुरंत रूट है। आप या तो नेविगेशन को सामान्य रूप से दिखा सकते हैं, या रूट ले सकते हैं और मौजूदा नेविगेशन में धक्का दे सकते हैं और काम करना जारी रख सकते हैं।

इस मामले में हमारा UserEditCoordinator केवल जेनेरिक पैरामीटर में इसके RootViewController के प्रकार को प्रतिस्थापित करते हुए, टाइपलेसिया बन जाएगा।

स्क्रिप्ट डेटा ट्रांसफर वापस


चलो आखिरी समस्या को हल करने के बारे में बात करते हैं, जिसे मैंने शुरुआत में रेखांकित किया था। यह स्क्रिप्ट में डेटा का स्थानांतरण है।



शहर चुनने के लिए समान परिदृश्य पर विचार करें, लेकिन अब एक शहर नहीं, बल्कि कई चुनना संभव होगा। उपयोगकर्ता को यह दिखाने के लिए कि उसने एक ही क्षेत्र के भीतर कई शहरों का चयन किया है, हम स्क्रीन पर इस क्षेत्र के नाम की एक छोटी संख्या वाले क्षेत्रों की सूची के साथ दिखाएंगे, जो इस क्षेत्र में चयनित शहरों की संख्या दिखाते हैं।

यह पता चला है कि एक नियंत्रक पर कार्रवाई (तीसरे पर) एक बार में कई अन्य लोगों की उपस्थिति में बदलाव के लिए नेतृत्व करना चाहिए। यही है, पहले हमें शहर के साथ सेल में दिखाना होगा, और दूसरे में हमें चयनित क्षेत्रों में सभी नंबरों को अपडेट करना होगा।

समन्वयक डेटा को स्क्रिप्ट में वापस स्थानांतरित करके इस कार्य को सरल बनाता है - यह अब स्क्रिप्ट के अनुसार डेटा को स्थानांतरित करने के रूप में सरल कार्य है।

यहाँ क्या हो रहा है? उपयोगकर्ता एक शहर का चयन करता है। यह संदेश समन्वयक को भेजा जाता है। समन्वयक, जैसा कि मैंने पहले ही डेमो में दिखाया है, पूरे नेविगेशन स्टैक से गुजरता है और सभी इच्छुक पार्टियों को अद्यतन डेटा भेजता है। तदनुसार, ViewController इस डेटा के साथ अपने दृश्य को अपडेट कर सकता है।

मौजूदा कोड Refactoring


यदि आप एक मौजूदा एप्लिकेशन जिसमें MVc, MVVm या MVp है, में इस कोड को एम्बेड करना चाहते हैं तो मौजूदा कोड को कैसे रिफ्लेक्टर करें?



आपके पास ViewController का एक गुच्छा है। पहली चीज उन्हें परिदृश्यों में विभाजित करना है जिसमें वे भाग लेते हैं। हमारे उदाहरण में, 3 परिदृश्य हैं: प्राधिकरण, प्रोफ़ाइल संपादन, टेप।



अब हम अपने समन्वयक के अंदर प्रत्येक परिदृश्य को लपेटते हैं। हमें अपने आवेदन में कहीं से भी इन लिपियों को शुरू करने में सक्षम होना चाहिए। यह लचीला होना चाहिए - समन्वयक को पूरी तरह से आत्मनिर्भर होना चाहिए

यह विकास दृष्टिकोण अतिरिक्त सुविधा प्रदान करता है। यह इस तथ्य में शामिल है कि यदि आप वर्तमान में एक विशिष्ट परिदृश्य के साथ काम कर रहे हैं, तो आपको हर बार इसे शुरू करने पर क्लिक करने की आवश्यकता नहीं है। आप इसे शुरू में जल्दी से शुरू कर सकते हैं, इसमें कुछ संपादित कर सकते हैं, और फिर इस अस्थायी शुरुआत को हटा सकते हैं।

अपने समन्वयकों पर निर्णय लेने के बाद, हमें यह निर्धारित करने की आवश्यकता है कि कौन सा परिदृश्य दूसरे की शुरुआत को जन्म दे सकता है, और इन परिदृश्यों से एक पेड़ बना सकता है।



हमारे मामले में, पेड़ सरल है: LoginCoordinator प्रोफ़ाइल संपादन समन्वयक शुरू कर सकता है। यहां, लगभग सब कुछ जगह में आता है, लेकिन एक बहुत ही महत्वपूर्ण विस्तार बना हुआ है - हमारी योजना में प्रवेश बिंदु का अभाव है।



यह प्रवेश बिंदु एक विशेष समन्वयक - ApplicationCoordinator होगा । यह AppDelegate द्वारा बनाया और शुरू किया गया है, और फिर यह पहले से ही आवेदन स्तर पर तर्क को नियंत्रित करता है, अर्थात, जो समन्वयक अब शुरू होता है।

हमने बस एक समान सर्किट को देखा, केवल इसमें समन्वयक के बजाय ViewController था, और हमने इसे इसलिए बनाया ताकि ViewController को एक-दूसरे के बारे में कुछ भी पता न चले और एक-दूसरे को डेटा पास न करें। सिद्धांत रूप में, समन्वयकों के साथ भी ऐसा ही किया जा सकता है। हम उनमें एक निश्चित इनपुट (प्रारंभ विधि) और आउटपुट (ऑनफिनिश कॉलबैक) नामित कर सकते हैं। समन्वयक स्वतंत्र, पुन: प्रयोज्य और आसानी से परीक्षण योग्य बन जाते हैं । समन्वयक एक-दूसरे के बारे में जानना और संवाद करना बंद कर देते हैं, उदाहरण के लिए, केवल ApplicationCoordinator के साथ।

आपको सावधान रहने की आवश्यकता है, क्योंकि यदि आपके आवेदन में इन लिपियों के लिए पर्याप्त है, तो ApplicationCoordinator एक विशाल ईश्वर-वस्तु में बदल सकता है, यह सभी मौजूदा लिपियों के बारे में पता चलेगा - यह भी बहुत अच्छा नहीं है। यहां हमें पहले से ही देखना चाहिए - शायद समन्वयकों को उप-समन्वयकों में विभाजित करें, अर्थात्, ऐसी वास्तुकला पर विचार करें ताकि ये ऑब्जेक्ट अविश्वसनीय आकार तक न बढ़ें। हालांकि आकार हमेशा रिफैक्टरिंग का कारण नहीं होता है

कहां से शुरू करें


मैं नीचे से शुरू करने की सलाह देता हूं - पहले व्यक्तिगत स्क्रिप्ट को लागू करें।



वर्कअराउंड के रूप में, उन्हें UIViewController के अंदर शुरू किया जा सकता है। यही है, जब तक आपके पास रूट या अन्य समन्वयक नहीं हैं, तब तक आप एक समन्वयक बना सकते हैं और, अस्थायी समाधान के रूप में, इसे UIViewController से शुरू कर सकते हैं, इसे स्थानीय रूप से संपत्ति में सहेज सकते हैं (जैसा कि nextCoordinator ऊपर है)। जब कोई घटना होती है, तो आप, जैसा कि मैंने डेमो में दिखाया है, एक स्थानीय संपत्ति बनाएं, समन्वयक को वहां रखें और उस पर प्रारंभ विधि को कॉल करें। सब कुछ बहुत सरल है।

फिर, जब ये सभी समन्वयक पहले ही कर चुके होते हैं, तो दूसरे के अंदर एक की शुरुआत बिल्कुल एक जैसी दिखती है। क्या आपके पास स्थानीय संपत्ति या किसी प्रकार की निर्भरता की सरणी है जैसे समन्वयक, आप यह सब वहां डालते हैं ताकि यह भाग न जाए, और प्रारंभ विधि को कॉल करें।

परिणाम


  • स्वतंत्र स्क्रीन और स्क्रिप्ट जो एक दूसरे के बारे में कुछ भी नहीं जानते हैं, एक दूसरे के साथ संवाद नहीं करते हैं। हमने इसे हासिल करने की कोशिश की।
  • एप्लिकेशन में स्क्रीन कोड बदलने के बिना स्क्रीन के क्रम को बदलना आसान है । यदि सब कुछ वैसा ही हो जाता है, जैसा कि स्क्रिप्ट के परिवर्तन के बाद ही अनुप्रयोग में बदलना चाहिए, स्क्रीन कोड नहीं है, बल्कि समन्वयक कोड है।
  • स्क्रीन और अन्य कार्यों के बीच सरलीकृत डेटा अंतरण जो स्क्रीन के बीच संबंध स्थापित करते हैं।
  • व्यक्तिगत रूप से, मेरा पसंदीदा क्षण यह है कि इसका उपयोग शुरू करने के लिए, आपको परियोजना में किसी भी तृतीय-पक्ष निर्भरता को जोड़ने और अन्य लोगों के कोड को समझने की आवश्यकता नहीं है

AppsConf 2018 पहले से ही 8 अक्टूबर और 9 वीं है - इसे याद मत करो! बल्कि, अनुसूची का अध्ययन करें (या उस पर समीक्षा करें) और टिकट बुक करेंस्वाभाविक रूप से, दोनों प्लेटफार्मों पर बहुत ध्यान दिया जाता है - आईओएस और एंड्रॉइड, वास्तुकला पर प्लस रिपोर्ट जो केवल एक तकनीक से बंधे नहीं हैं, और मोबाइल विकास के आसपास की दुनिया से संबंधित अन्य महत्वपूर्ण मुद्दों की चर्चा है।

Source: https://habr.com/ru/post/hi423299/


All Articles