कंबाइन के लिए तैयार हो रही है



डेढ़ साल पहले, मैंने RxSwift की प्रशंसा की । मुझे यह पता लगाने में थोड़ा समय लगा, लेकिन जब ऐसा हुआ, तो पीछे मुड़कर नहीं देखा गया। अब मेरे पास दुनिया का सबसे अच्छा हथौड़ा था, और मुझे धिक्कार है अगर मेरे आसपास सब कुछ एक नाखून की तरह नहीं लगता था।

Apple ने WWDC समर कॉन्फ्रेंस में कॉम्बिनेशन की रूपरेखा पेश की। पहली नज़र में यह RxSwift का थोड़ा बेहतर संस्करण लगता है। इससे पहले कि मैं समझा सकूं कि मुझे इसके बारे में क्या पसंद है और क्या नहीं, हमें यह समझने की जरूरत है कि कंबाइन को हल करने के लिए क्या समस्या है।

प्रतिक्रियाशील प्रोग्रामिंग? तो क्या?


ReactiveX समुदाय - जिनमें से RxSwift समुदाय एक हिस्सा है - इसका सार इस प्रकार है:

अवलोकन योग्य थ्रेड के साथ अतुल्यकालिक प्रोग्रामिंग के लिए एपीआई।

और यह भी:

ReactiveX ऑब्जर्वर और Iterator डिजाइन पैटर्न, साथ ही कार्यात्मक प्रोग्रामिंग से सर्वश्रेष्ठ विचारों का एक संयोजन है।

अच्छा ... ठीक है।

और इसका वास्तव में क्या मतलब है?

मूल बातें


वास्तव में प्रतिक्रियाशील प्रोग्रामिंग के सार को समझने के लिए, मुझे यह समझना उपयोगी है कि हमें यह कैसे मिला। इस लेख में मैं वर्णन करूंगा कि आप किसी भी आधुनिक ओओपी भाषा में मौजूदा प्रकारों को कैसे देख सकते हैं, उन्हें मोड़ सकते हैं, और फिर प्रतिक्रियाशील प्रोग्रामिंग पर आ सकते हैं।

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

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

तो अगर आप नए विवरण में रुचि रखते हैं तो मेरी अगली पोस्ट की प्रतीक्षा करें।

गणनीय


मेरे लिए ज्ञात " रिएक्टिव प्रोग्रामिंग " उस भाषा में उत्पन्न हुआ जिसमें मैंने एक बार लिखा था - सी #। आधार ही काफी सरल है:

क्या होगा यदि, मानों को गणना से निकालने के बजाय, वे आपको स्वयं मान भेजेंगे?

यह विचार, "पुल के बजाय धक्का", सबसे अच्छा ब्रायन बेकमैन और एरिक मेयर द्वारा वर्णित किया गया था। पहले 36 मिनट ... मुझे कुछ समझ में नहीं आया, लेकिन 36 वें मिनट से शुरू होकर यह वास्तव में दिलचस्प हो गया।

संक्षेप में, आइए स्विफ्ट में वस्तुओं के एक रैखिक समूह के विचार में सुधार करें, साथ ही एक वस्तु जो इस रैखिक समूह पर पुनरावृति कर सकती है। आप इन नकली स्विफ्ट प्रोटोकॉल को परिभाषित करके कर सकते हैं:

//   ;     //    Array. protocol Enumerable { associatedtype Enum: Enumerator associatedtype Element where Self.Element == Self.Enum.Element func getEnumerator() -> Self.Enum } // ,       . protocol Enumerator: Disposable { associatedtype Element func moveNext() throws -> Bool var current: Element { get } } //          // Enumerator,         .   . protocol Disposable { func dispose() } 

डबल्स


चलो इसे सब खत्म कर देते हैं और युगल बनाते हैं। हम डेटा भेजेंगे कि वे कहां से आए हैं। और डेटा प्राप्त करें जहां से उन्होंने छोड़ा था। यह बेतुका लगता है, लेकिन इसे थोड़ा सहन करें।

डबल प्रवेश करने योग्य


चलो Enumerable से शुरू करते हैं:

 //    ,  . protocol Enumerable { associatedtype Element where Self.Element == Self.Enum.Element associatedtype Enum: Enumerator func getEnumerator() -> Self.Enum } protocol DualOfEnumerable { //  Enumerator : // getEnumerator() -> Self.Enum //    : // getEnumerator(Void) -> Enumerator // //  , : // : Void; : Enumerator // getEnumerator(Void) → Enumerator // //     Void   Enumerator. //   -      Enumerator,   Void. // :  Enumerator; : Void func subscribe(DualOfEnumerator) } 

चूंकि getEnumerator() ने Void लिया और Enumerator दिया, अब हम [Double] Enumerator स्वीकार करते हैं और Void देते हैं।

मुझे पता है यह अजीब है। छोड़ना नहीं है।

डबल एन्यूमरेटर


और फिर DualOfEnumerator क्या है?

 //    ,  . protocol Enumerator: Disposable { associatedtype Element // : Void; : Bool, Error func moveNext() throws -> Bool // : Void; : Element var current: Element { get } } protocol DualOfEnumerator { // : Bool, Error; : Void //   Error    func enumeratorIsDone(Bool) // : Element, : Void var nextElement: Element { set } } 

यहाँ कई मुद्दे हैं:

  • स्विफ्ट में केवल-सेट संपत्ति की कोई अवधारणा नहीं है।
  • Enumerator.moveNext() में throws साथ क्या हुआ?
  • क्या होता है Disposable ?

सेट-ओनली प्रॉपर्टी के साथ समस्या को ठीक करने के लिए, हम इसका इलाज कर सकते हैं कि यह वास्तव में क्या है - एक फ़ंक्शन। चलो हमारे DualOfEnumerator करें:

 protocol DualOfEnumerator { // : Bool; : Void, Error //   Error    func enumeratorIsDone(Bool) // : Element, : Void func next(Element) } 

throws साथ समस्या को हल करने के लिए, आइए moveNext() अलग करें जो हो सकता है moveNext() और एक अलग error() रूप में इसके साथ काम करें error() :

 protocol DualOfEnumerator { // : Bool, Error; : Void func enumeratorIsDone(Bool) func error(Error) // : Element, : Void func next(Element) } 

हम कुछ और कर सकते हैं: पुनरावृत्ति के पूरा होने के हस्ताक्षर पर एक नज़र डालें:

 func enumeratorIsDone(Bool) 

संभवतः समय के साथ भी कुछ ऐसा ही होगा:

 enumeratorIsDone(false) enumeratorIsDone(false) //     enumeratorIsDone(true) 

अब, चीजों को सरल करते हैं और enumeratorIsDone कॉल करते हैं जब ... सब कुछ वास्तव में तैयार है। इस विचार द्वारा निर्देशित, हम कोड को सरल करते हैं:

 protocol DualOfEnumerator { func enumeratorIsDone() func error(Error) func next(Element) } 

अपना ख्याल रखना


Disposable बारे में क्या? इससे क्या लेना-देना? चूंकि Disposable Enumerator प्रकार का हिस्सा है , जब हम Enumerator डबल प्राप्त करते हैं, तो यह संभवत: Enumerator में नहीं होना चाहिए। इसके बजाय, यह DualOfEnumerable हिस्सा होना चाहिए। लेकिन वास्तव में कहाँ?

यहां DualOfEnumerator :

 func subscribe(DualOfEnumerator) 

यदि हम DualOfEnumerator स्वीकार करते हैं, तो क्या Disposable को वापस नहीं किया जाना चाहिए?

यहां बताया गया है कि अंत में आपको किस तरह का डबल मिलेगा:

 protocol DualOfEnumerable { func subscribe(DualOfEnumerator) -> Disposable } protocol DualOfEnumerator { func enumeratorIsDone() func error(Error) func next(Element) } 

इसे गुलाब कहें, हालांकि नहीं


तो, एक और समय, यहाँ हमें क्या मिला:

 protocol DualOfEnumerable { func subscribe(DualOfEnumerator) -> Disposable } protocol DualOfEnumerator { func enumeratorIsDone() func error(Error) func next(Element) } 

आइए अब नामों के साथ थोड़ा खेलते हैं।

शुरुआत करते हैं DualOfEnumerator । हम कार्यों के लिए बेहतर नामों के साथ आएंगे और अधिक सटीक रूप से वर्णन करेंगे कि क्या हो रहा है:

 protocol DualOfEnumerator { func onComplete() func onError(Error) func onNext(Element) } 

इतना बेहतर और अधिक समझ में आता है।

टाइप नामों के बारे में क्या? वे सिर्फ भयानक हैं। चलो उन्हें थोड़ा बदल दें।

  • DualOfEnumerator - वस्तुओं के एक रैखिक समूह के साथ जो कुछ होता है वह कुछ इस प्रकार है। हम कह सकते हैं कि वह एक रेखीय समूह का अवलोकन करता है।
  • DualOfEnumerable अवलोकन का विषय है। जो हम देख रहे हैं। इसलिए इसे अवलोकनीय कहा जा सकता है

अब अंतिम परिवर्तन करें और निम्नलिखित प्राप्त करें:

 protocol Observable { func subscribe(Observer)Disposable } protocol Observer { func onComplete() func onError(Error) func onNext(Element) } 

वाह


हमने अभी RxSwift में दो मूलभूत वस्तुएँ बनाई हैं। आप उनके असली संस्करण यहां और यहां देख सकते हैं। ध्यान दें कि ऑब्जर्वर के मामले में, तीनों on() फ़ंक्शन को एक on(Event) एक में जोड़ दिया जाता है, जहां Event एक एन्यूमरेशन होता है जो निर्धारित करता है कि ईवेंट क्या है - पूर्ण, अगला मान या त्रुटि।

ये दो प्रकार RxSwift और प्रतिक्रियाशील प्रोग्रामिंग को रेखांकित करते हैं।

नकली प्रोटोकॉल के बारे में


जिन दो "नकली" प्रोटोकॉल का मैंने ऊपर उल्लेख किया है, वे वास्तव में नकली नहीं हैं। ये स्विफ्ट में मौजूदा प्रकार के एनालॉग हैं:


तो क्या?


तो चिंता किस बात की?

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

आधुनिक कोकोआटोक दुनिया में, इस तरह की घटनाओं को संभालने के कई तरीके हैं:

  • अधिसूचना (नोटिफिकेशन),
  • कॉलबैक कार्य (कॉलबैक) ,,
  • कुंजी-मूल्य अवलोकन (KVO),
  • लक्ष्य / कार्रवाई तंत्र।

कल्पना कीजिए कि क्या यह सब एक एकल इंटरफ़ेस में परिलक्षित हो सकता है। जो संपूर्ण अनुप्रयोग के भीतर किसी भी प्रकार के अतुल्यकालिक डेटा या घटनाओं के साथ काम कर सकता है।

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

अचानक, हमारे हाथों में उपकरणों का एक नया सार्वभौमिक सेट है।
और इसलिए, हम शुरुआत में लौट आए:

अवलोकन योग्य थ्रेड के साथ अतुल्यकालिक प्रोग्रामिंग के लिए एपीआई।

यह वही है जो RxSwift को इतना शक्तिशाली उपकरण बनाता है। कंबाइन की तरह।

आगे क्या है?


यदि आप अभ्यास में RxSwift के बारे में अधिक पढ़ना चाहते हैं, तो मैं 2016 में लिखे गए मेरे पांच लेखों की सिफारिश करता हूं । वे एक साधारण कोकोआउंट एप्लिकेशन के निर्माण का वर्णन करते हैं, इसके बाद RxSwift में एक चरणबद्ध रूपांतरण होता है।

निम्नलिखित लेखों में से एक में मैं बताऊंगा कि शुरुआती लोगों के लिए मेरी लेख श्रृंखला में वर्णित तकनीकों में से कई संयोजन में लागू नहीं हैं, और मैं RxSwift के साथ संयोजन की तुलना भी करता हूं।

गठबंधन: क्या बात है?


कंबाइन की चर्चा में इसके और RxSwift के बीच मुख्य अंतर की चर्चा भी शामिल है। मेरे लिए उनमें से तीन हैं:

  • गैर-प्रतिक्रियाशील वर्गों का उपयोग करने की संभावना,
  • त्रुटि से निपटने
  • backpressure।

मैं प्रत्येक आइटम के लिए एक अलग लेख समर्पित करूंगा। मैं पहले वाले से शुरुआत करूंगा।

RxCocoa की विशेषताएं


पिछली पोस्ट में, मैंने कहा था कि RxSwift से अधिक है ... RxSwift। यह RxCocoa के प्रकार-लेकिन-नहीं-काफी उपप्रोजेक्ट में UIKit से नियंत्रण का उपयोग करने के लिए कई संभावनाएं प्रदान करता है। इसके अलावा, RxSwiftCommunity ने आगे बढ़कर UIKit की और भी एकांत सड़कों पर कई बाइंडिंग लागू की, साथ ही साथ कुछ अन्य कोकोआटच क्लासेस कि RxSwift और RxCocoa को अभी तक कवर नहीं किया है।

इसलिए, UIButton पर क्लिक करना, कहना, एक Observable स्ट्रीम प्राप्त करना बहुत आसान है। मैं इस उदाहरण को फिर से दूंगा:

 let disposeBag = DisposeBag() let button = UIButton() button.rx.tap .subscribe(onNext: { _ in print("Tap!") }) .disposed(by: disposeBag) 

हल्के वजन।

आइए (अंत में) अभी भी कॉम्बाइन के बारे में बात करते हैं


कंबाइन RxSwift के समान है। जैसा कि प्रलेखन कहता है:

कंबाइन फ्रेमवर्क समय के साथ मूल्यों को संभालने के लिए एक घोषणात्मक स्विफ्ट एपीआई प्रदान करता है।

परिचित लगता है: ReactiveX (RxSwift के लिए मूल परियोजना) के विवरण को याद करें:

अवलोकन योग्य थ्रेड के साथ अतुल्यकालिक प्रोग्रामिंग के लिए एपीआई।

दोनों मामलों में, एक ही बात कही जाती है। यह सिर्फ इतना है कि ReactiveX के विवरण में विशिष्ट शब्दों का उपयोग किया जाता है। इसे निम्नानुसार सुधारा जा सकता है:

समय के साथ मूल्यों के साथ अतुल्यकालिक प्रोग्रामिंग के लिए एक एपीआई।

मेरे लिए लगभग वैसा ही।

पहले जैसा ही


जब मैंने एपीआई का विश्लेषण करना शुरू किया, तो यह तुरंत स्पष्ट हो गया कि मैं RxSwift से जिन प्रकारों को जानता हूं उनमें से अधिकांश के संयोजन में समान विकल्प हैं:

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

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

और भी बेहतर है!

  • RxCocoa का ड्राइवर -> यह स्विफ्टयूआई से BindableObject है

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


"ब्रेक फॉर पूप"


RxCocoa में देरी करते ही सब कुछ बदल जाता है। उपरोक्त उदाहरण को याद रखें, जिसमें हम एक अवलोकन योग्य धारा प्राप्त करना चाहते थे जो UIButton पर क्लिक का प्रतिनिधित्व करती है? यहाँ यह है:

 let disposeBag = DisposeBag() let button = UIButton() button.rx.tap .subscribe(onNext: { _ in print("Tap!") }) .disposed(by: disposeBag) 

कंबाइन की आवश्यकता होती है ... और भी बहुत कुछ करने के लिए।

कंबाइन UIKit ऑब्जेक्ट के लिए बाध्य करने के लिए कोई क्षमता प्रदान नहीं करता है।

यह है ... सिर्फ एक अवास्तविक bummer।

यहां UIControl प्राप्त करने का एक सामान्य तरीका है। Combine का उपयोग करके UIControl से दूर रहें :

 class ControlPublisher<T: UIControl>: Publisher { typealias ControlEvent = (control: UIControl, event: UIControl.Event) typealias Output = ControlEvent typealias Failure = Never let subject = PassthroughSubject<Output, Failure>() convenience init(control: UIControl, event: UIControl.Event) { self.init(control: control, events: [event]) } init(control: UIControl, events: [UIControl.Event]) { for event in events { control.addTarget(self, action: #selector(controlAction), for: event) } } @objc private func controlAction(sender: UIControl, forEvent event: UIControl.Event) { subject.send(ControlEvent(control: sender, event: event)) } func receive<S>(subscriber: S) where S : Subscriber, ControlPublisher.Failure == S.Failure, ControlPublisher.Output == S.Input { subject.receive(subscriber: subscriber) } } 

यहाँ ... बहुत अधिक काम। कम से कम कॉल की तरह दिखता है:

 ControlPublisher(control: self.button, event: .touchUpInside) .sink { print("Tap!") } 

तुलना के लिए, RxCocoa, UIKit वस्तुओं को बाइंडिंग के रूप में एक सुखद, स्वादिष्ट कोको प्रदान करता है:

 self.button.rx.tap .subscribe(onNext: { _ in print("Tap!") }) 

अपने आप से, ये चुनौतियाँ अंततः बहुत समान हैं। केवल निराशा की बात यह है कि मुझे इस बिंदु पर पहुंचने के लिए खुद को ControlPublisher लिखना पड़ा। इसके अलावा, RxSwift और RxCocoa का परीक्षण बहुत अच्छी तरह से किया जाता है और मेरा उपयोग परियोजनाओं की तुलना में बहुत अधिक किया जाता है।

तुलना के लिए, मेरा ControlPublisher केवल ... अब दिखाई दिया। केवल ग्राहकों की संख्या (शून्य) और वास्तविक दुनिया में उपयोग के समय (RxCocoa की तुलना में लगभग शून्य) की वजह से मेरे कोड को असीम रूप से अधिक खतरनाक माना जा सकता है।

ओह।

सामुदायिक मदद?


ईमानदारी से, कुछ भी समुदाय को अपने स्वयं के खुले स्रोत "कॉम्बीनेकोआ" को बनाने से रोकता है, जो कि आरएक्ससोफैकोमुनिटी की तरह ही आरएक्सकोकोआ गैप को भर देगा।

हालाँकि, मैं इसे कम्बाइन की बहुत बड़ी कमी मानता हूँ। मैं पूरे RxCocoa को फिर से लिखना नहीं चाहता, केवल UIKit ऑब्जेक्ट्स के लिए बाइंडिंग प्राप्त करना।

अगर मैं स्विफ्टयूआई पर दांव लगाने का फैसला करता हूं , तो मुझे लगता है कि इससे बाइंडिंग में कमी की समस्या खत्म हो जाएगी। यहां तक ​​कि मेरे छोटे अनुप्रयोग में UI कोड का एक गुच्छा होता है। कंबाइन ट्रेन पर कूदने के लिए यह सब बाहर फेंकना कम से कम बेवकूफी होगी, या खतरनाक भी।

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

उदाहरण


चलिए प्रलेखन के अंत में चलते हैं, जहाँ कोड उदाहरण है:

 let sub = NotificationCenter.default .publisher(for: NSControl.textDidChangeNotification, object: filterField) .map( { ($0.object as! NSTextField).stringValue } ) .assign(to: \MyViewModel.filterString, on: myViewModel) 

मुझे ... इसके साथ बहुत सारी समस्याएं हैं।

आपको सूचित करता हूं कि मुझे यह पसंद नहीं है


पहली दो पंक्तियाँ मेरे लिए सबसे अधिक सवाल पैदा करती हैं:

 let sub = NotificationCenter.default .publisher(for: NSControl.textDidChangeNotification, object: filterField) 

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

लेकिन मेरे लिए NotificationCenter एक चोक के साथ कोड है । ऐसे समय होते हैं (जैसे कीबोर्ड के बारे में सूचना प्राप्त करना) जब नोटिफिकेशनकेंटर वास्तव में समस्या का सबसे अच्छा संभव समाधान होता है। लेकिन बहुत बार मेरे लिए NotificationCenter सबसे सुविधाजनक समाधान है। यह NotificationCenter में कुछ ड्रॉप करने और आवेदन में कहीं और इसे लेने के लिए वास्तव में बहुत सुविधाजनक है।

इसके अलावा, NotificationCenter "स्ट्रिंग" -typed है , अर्थात, आप आसानी से गलती कर सकते हैं कि आप किस अधिसूचना को प्रकाशित या सुनने की कोशिश कर रहे हैं। स्विफ्ट स्थिति को सुधारने के लिए हर संभव कोशिश कर रहा है, लेकिन फिर भी वही एनएसएसट्रिंग अभी भी हुड के नीचे है।

केवीओ के बारे में


Apple प्लेटफ़ॉर्म पर, लंबे समय से कोड के विभिन्न भागों में परिवर्तन की सूचनाएं प्राप्त करने का एक लोकप्रिय तरीका है: कुंजी-मूल्य अवलोकन (KVO)। Apple इसे इस तरह वर्णन करता है:

यह एक तंत्र है जो वस्तुओं को अन्य वस्तुओं के निर्दिष्ट गुणों में परिवर्तन की सूचना प्राप्त करने की अनुमति देता है।

एक गुई रेम्बो ट्वीट के लिए धन्यवाद , मैंने देखा कि एप्पल ने केवीओ बाइंडिंग को कॉम्बिनेशन में जोड़ा। इसका मतलब यह हो सकता है कि मैं कंबाइन में RxCocoa एनालॉग की कमी के बारे में कई निराशाओं से छुटकारा पा सकता हूं। यदि मैं केवीओ का उपयोग कर सकता हूं, तो यह संभवतः कॉम्बिनेकोआ की आवश्यकता को समाप्त कर देगा, इसलिए बोलने के लिए।

मैंने KVO का उपयोग करके UITextField से मान प्राप्त करने और इसे कंसोल पर आउटपुट करने का एक उदाहरण जानने की कोशिश की:

 let sub = self.textField.publisher(for: \UITextField.text) .sink(receiveCompletion: { _ in print("Completed") }, receiveValue: { print("Text field is currently \"\($0)\"") }) 

अच्छा लग रहा है, आगे बढ़ें?

इतनी जल्दी नहीं, दोस्तों।

मैं असहज सत्य के बारे में भूल गया:

UIKit, बाय और लार्ज, KVO के अनुकूल नहीं है।

और केवीओ समर्थन के बिना, मेरा विचार काम नहीं करेगा। मेरे चेक ने इस बात की पुष्टि की: जब मैं फ़ील्ड में टेक्स्ट दर्ज करता हूं, तो कोड कंसोल को कुछ भी आउटपुट नहीं करता है।

इसलिए, UIKit बाइंडिंग की आवश्यकता से छुटकारा पाने की मेरी उम्मीदें सुंदर थीं, लेकिन लंबे समय तक नहीं।

सफाई


एक और संयुक्त समस्या यह है कि यह अभी भी पूरी तरह से स्पष्ट नहीं है कि कैंसेलेबल वस्तुओं में संसाधनों को कहाँ और कैसे मुक्त किया जाए। ऐसा लगता है कि हमें उन्हें उदाहरण चर में संग्रहीत करना चाहिए। लेकिन मुझे याद नहीं है कि आधिकारिक दस्तावेज में सफाई के बारे में कुछ कहा गया था।

RxSwift में एक बहुत नाम-पर-अविश्वसनीय-सुविधाजनक डिस्पोज़ब है । कम्बाइन को कम्बाइन में बनाना कोई कम आसान नहीं है, लेकिन मुझे यकीन नहीं है कि इस मामले में यह सबसे अच्छा समाधान है।

अगले लेख में हम RxSwift और Combine में त्रुटि से निपटने के बारे में बात करेंगे, दोनों दृष्टिकोणों के फायदे और नुकसान के बारे में।

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


All Articles