2016-08-18 19 views
12

स्विफ्ट 3 (एक्सकोड 8 बीटा 6) में रिकर्सिव प्रोटोकॉल बाधाओं की कमी के आसपास काम करना वर्तमान में "रिकर्सिव प्रोटोकॉल बाधाओं" के संबंध में एक सीमा है। here एक खुली समस्या है, और here, here और here पर समान चर्चाएं चल रही हैं। हालांकि, मैं अभी भी यह देखने में असफल रहा कि इस सीमा के आसपास किसी को कैसे काम करना चाहिए। क्या यह संभव है?स्विफ्ट 3

के एक दृश्य के चारों ओर एक दृश्य के मॉडल और अन्य तरीके से संदर्भित करने का सरल उदाहरण पर विचार करें और साथ ही किसी भी चक्र को बनाए रखने के रूप में रेफरी/मूल्य प्रकार पर विचार नहीं करने देता है:

protocol ViewModelType { 
    associatedtype V: ViewType 
    var view: V { get } 
} 

struct ViewModel<V: ViewType>: ViewModelType { 
    var view: V 
} 


protocol ViewType { 
    associatedtype VM: ViewModelType 
    var viewModel: VM { get } 
} 

struct View<VM: ViewModelType>: ViewType { 
    var viewModel: VM 
} 

ऊपर कोड आप चलेंगे साथ प्रदत्त लिंक में चर्चा के अनुसार Type may not reference itself as a requirement में।

तब (अनुभवहीन के रूप में मैं कर रहा हूँ), मैंने सोचा कि मैं इस के आसपास करके काम कर सकता था:

protocol _ViewModelType {} 
protocol ViewModelType: _ViewModelType { 
    associatedtype V: _ViewType 
    var view: V { get } 
} 

struct ViewModel<V: ViewType>: ViewModelType { 
    var view: V 
} 


protocol _ViewType {} 
protocol ViewType: _ViewType { 
    associatedtype VM: _ViewModelType 
    var viewModel: VM { get } 
} 

struct View<VM: ViewModelType>: ViewType { 
    var viewModel: VM 
} 

यह त्रुटि को मारता है, लेकिन यह मूल रूप से बस समस्या स्थगित। क्योंकि अब जब हम अपने ठोस प्रकार का निर्माण करना चाहते हैं, हम विशेषज्ञता के बारे में कभी न खत्म होने पाश में खत्म हो:

let vm = ViewModel<View<ViewModel<View...>>>() 

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

अद्यतन अगस्त 19, वर्ष 2016

इस समस्या के समाधान के लिए सबसे अच्छा तरीका यह पता लगाने की एक बहुत कोशिश के बाद, मेरा मानना ​​है कि मैं एक समाधान है कि स्वीकार्य है और केवल पाया है कम से कम समझौते की आवश्यकता है:

protocol ViewModelType { 
    associatedtype D: Any // Compromise to avoid the circular protocol constraints. 
    var delegate: D? { get set } 
} 

protocol ViewType { 
    associatedtype VM: ViewModelType 
    var viewModel: VM { get } 
} 

protocol ViewDelegate { 
    func foo() 
} 


struct ViewModel: ViewModelType { 
    typealias D = ViewDelegate 
    var delegate: D? 

    func bar() { 
     delegate?.foo() // Access to delegate methods 
    } 
} 

struct View<VM: ViewModelType>: ViewType, ViewDelegate { 
    var viewModel: VM 

    func foo() { 
     // Preferred, but not possible: viewModel.delegate = self 
    } 
} 


var vm = ViewModel() // Type: ViewModel 
let v = View(viewModel: vm) // Type: View<ViewModel> 
vm.delegate = v 

मुख्य विचार यह है कि, मध्यस्थ वस्तु या एक प्रतिनिधि वस्तु पेश की जाती है, दृश्य और दृश्य मॉडल के बीच संचार को संभालने के लिए। परिपत्र प्रोटोकॉल बाधाओं को तोड़ने के लिए इस प्रतिनिधि का संदर्भ Any प्रकार है। जैसा कि मैंने इसे देखा है, केवल नकारात्मक पक्ष यह है कि प्रतिनिधि को "बाहरी से" स्थापित करने की आवश्यकता होती है, जहां से वस्तुओं को बनाया जाता है, और View कार्यान्वयन में सेट नहीं किया जा सकता है। अगर कोई ऐसा करने का प्रयास करता है, तो त्रुटि Cannot assign value of type View<VM> to type _? दिखाई देगी।

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

उत्तर

1

आप उपयोग करने के लिए किसी कारण/भाषा कमियों तक स्पष्ट रूप से डाली जब View.foo में प्रतिनिधि बताए: viewModel.delegate = self as? VM.D

लेकिन आप structs और नहीं कक्षाएं क्यों प्रयोग करते हैं?मुझे लगता है कि आप कक्षाएं चाहते हैं, expecially आप नहीं करना चाहते हैं उन सभी देखें/ViewModel चर के आसपास प्रतिलिपि बनाई जा रही है, जबकि संशोधित - बजाय संदर्भित किया जा रहा की - जब आप

var vm = ViewModel() // Type: ViewModel 
let v = View(viewModel: vm) // Type: View<ViewModel> 
vm.delegate = v 

विशेष रूप से

func foo() { 
    viewModel.delegate = self 
} 

नहीं करता है की तरह कुछ करना 'टी काम जब तक आप mutating रूप View.foo ऐलान करते हैं और इस mutating और v = View(viewModel: vm) किए जाने के लिए किसी भी अधिक एक निरंतर नहीं किया जा सकता (ViewDelegate.foo और ViewModel.bar सहित) लगभग सब कुछ की आवश्यकता होगी। , क्यों आप अपना दृश्य वर्ग के प्रारंभकर्ता में किसी प्रकार है:

हालांकि नीचे समाधान भी structs के साथ काम करेगा, मैं सिर्फ प्रत्येक भाग को कक्षाओं के लिए बदल दिया है:

protocol ViewModelType { 
    associatedtype D: Any // Compromise to avoid the circular protocol constraints. 
    var delegate: D? { get set } 
} 

protocol ViewType { 
    associatedtype VM: ViewModelType 
    var viewModel: VM { get } 
} 

protocol ViewDelegate { 
    func foo() 
} 


class ViewModel: ViewModelType { 
    typealias D = ViewDelegate 
    var delegate: D? 

    func bar() { 
     delegate?.foo() // Access to delegate methods 
    } 
} 

class View<VM: ViewModelType>: ViewType, ViewDelegate { 
    var viewModel: VM 

    // initializer needed, because we are no struct any more 
    init(viewModel vm:VM) { 
     self.viewModel = vm 
    } 

    func foo() { 
     viewModel.delegate = self as? VM.D 
    } 
} 


var vm = ViewModel() // Type: ViewModel 
let v = View(viewModel: vm) // Type: View<ViewModel> 
v.foo()  // View<ViewModel> 
vm.delegate // View<ViewModel> 

सिर्फ एक और बात नहीं है जैसे:

// initializer needed, because we are no struct any more 
init(viewModel vm:VM) { 
    self.viewModel = vm 
    self.viewModel.delegate = self as? VM.D 
} 

तो फिर तुम प्रतिनिधि सेट करने के लिए v.foo() करने के लिए कॉल को छोड़ सकता है।

+0

यह बेहतर है, धन्यवाद! मुझे लगता है, यह करीब है क्योंकि हम स्विफ्ट के वर्तमान संस्करण के साथ मिल सकते हैं। –