2017-03-13 11 views
9

पर आधारित जेनेरिक पैरामीटर मान के साथ UITableViewCell पर उप-वर्ग पर कॉल विधि UITableViewCell उप-वर्गों में "सेटअप"-विधि के कॉलिंग को सरल बनाना चाहते हैं। हालांकि, सभी सेटअप विधियां समान नहीं हैं, लेकिन उनके पैरामीटर एक ही प्रकार से प्राप्त होते हैं। क्या जेनरिक्स या प्रोटोकॉल के साथ हर बार पैरामीटर डालना नहीं है?प्रोटोकॉल या बेस क्लास

सबसे पहले मैं इस तरह एक cellForRow-विधि:

class DataSource<V : UIViewController, T: TableViewCellData, VM: ViewModel> : NSObject, UITableViewDataSource, UITableViewDelegate { 

    var dataCollection: TableViewDataCollection<T>! 
    var viewModel: VM! 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cellData = dataCollection.object(for: indexPath) 
     let cell = tableView.dequeueReusableCell(withIdentifier: cellData.identifier(), for: indexPath) 
     if let setupableCell = cell as? CellDataSetupable { 
      setupableCell.setup(with: cellData, viewModel: viewModel) 
     } 
     return cell 
    } 
} 

protocol CellDataSetupable : class { 
    func setup(with cellData: TableViewCellData, viewModel: ViewModel) 
} 

जहाँ मैं सेटअप cellData और ViewModel के साथ सेल।

मेरी (कई) कस्टम UITableViewCell उपवर्ग में:

extension BlurbTableViewCell : CellDataSetupable { 
    func setup(with cellData: TableViewCellData, viewModel: ViewModel) { 
     guard let cellData = cellData as? HomeViewTableViewCellData else { return } 
     guard let viewModel = viewModel as? HomeViewModel else { return } 

     // Use cellData and viewModel to setup cell appearance 
    } 
} 

जहां HomeViewTableViewCellDataTableViewCellData और HomeViewModel के उपवर्ग है ViewModel

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

extension BlurbTableViewCell : CellDataSetupable< { 
    func setup(with cellData: HomeViewTableViewCellData, viewModel: HomeViewModel) { 
     // Use cellData and viewModel to setup cell appearance 
    } 
} 

का प्रयास किया गया रों olutions (वह काम नहीं करता):

  • हालांकि, मैं associatedtype उपयोग नहीं कर सकते/प्रोटोकॉल पर typealias के रूप में यह एक त्रुटि प्रोटोकॉल cellForRow विधि में "कास्टिंग पर पैदा करता है ... केवल एक सामान्य बाधा के रूप में इस्तेमाल किया जा सकता क्योंकि इसमें स्वयं या संबंधित प्रकार की आवश्यकताएं हैं "। "Unknown class in interface builder file" when using class which inherits from a generic class in a Storyboard

  • मैं भी एक सामान्य baseclass उपयोग नहीं कर सकते के रूप में इंटरफ़ेस बिल्डर तो दुर्घटना होगा:: मैं इस विधि की कोशिश की How to create generic protocols in Swift? (यह भी देखें नीचे स्थित संपादित 2)

कोई भी विचार या मैं साथ रहने के लिए है मेरी कास्टिंग?

संपादित करें 1: नैट मान से नीचे दिए गए सुझावों मैं इस कोड (ध्यान दें कि मैं कुछ सामान्य प्रकार का नया नाम दिया है) की कोशिश की करने के बाद:

// This works fine 
extension TransactionTableViewCell : CellDataSetupable { 
    typealias CellData = HomeViewTableViewCellData 
    typealias VM = HomeViewModel 
    func setup(with cellData: CellData, viewModel: VM) { 
     //Setup cell appearance ... 
    } 
} 

यह पंक्ति भी ठीक काम करता है: (ध्यान दें अतिरिक्त जहां खंड)

class DataSource<VC : UIViewController, TVCD: TableViewCellData, VM: ViewModel, CDS: CellDataSetupable> : NSObject, UITableViewDataSource, UITableViewDelegate where CDS.TVCD == TVCD, CDS.VM == VM { 
    // ... 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cellData = dataCollection.object(for: indexPath) 
     let cell = tableView.dequeueReusableCell(withIdentifier: cellData.identifier(), for: indexPath) 
     if let setupableCell = cell as? CDS { 
      setupableCell.setup(with: cellData, viewModel: viewModel) 
     } 
     return cell 
    } 

लेकिन

class HomeTableViewDataSource: DataSource<HomeViewController, HomeViewTableViewCellData, HomeViewModel> { 
से बदल रहा है एक UITableViewCell वर्ग के लिए एक सामान्य baseclass का एक ठोस संस्करण का उपयोग करना या तो संभव नहीं है:

Using 'CellDataSetupable' as a concrete type confirming to protocol 'CellDataSetupable' is not supported 

संपादित करें 2:

को
class HomeTableViewDataSource: DataSource<HomeViewController, HomeViewTableViewCellData, HomeViewModel, CellDataSetupable> { 

इस त्रुटि दे। Why can't interface builder use a concrete generic subclass of of UIView?

उत्तर

0

मेरा उत्तर का यह विचार यह है कि इस समय यह संभव नहीं है।

नैट मान के जवाब CellDataSetupable है जो मैं नहीं चाहता की एक ठोस कार्यान्वयन निर्दिष्ट करने के लिए मुझे आवश्यकता है।

timaktimak के जवाब या तो साथ ही साथ एक ठोस कार्यान्वयन की जरूरत है या एक UIView की उपवर्गीकरण की आवश्यकता है।

1

मुझे लगता है कि यह काम करना चाहिए:

class DataSource<V : UIViewController, T: TableViewCellData, VM: ViewModel, X: CellDataSetupable> : NSObject where X.M == VM, X.T == T { 

    var dataCollection: TableViewDataCollection! 
    var viewModel: VM! 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cellData = dataCollection.object(for: indexPath) as! T 
     let cell = tableView.dequeueReusableCell(withIdentifier: cellData.identifier(), for: indexPath) 
     if let setupableCell = cell as? X { 
      setupableCell.setup(with: cellData, viewModel: viewModel) 
     } 
     return cell 
    } 
} 


protocol CellDataSetupable: class { 
    associatedtype T: TableViewCellData 
    associatedtype M: ViewModel 
    func setup(with cellData: T, viewModel: M) 
} 


class BlurbTableViewCell: UITableViewCell, CellDataSetupable { 
    func setup(with cellData: HomeViewTableViewCellData, viewModel: HomeViewModel) { 

     // Use cellData and viewModel to setup cell appearance 
    } 
} 
+0

कृपया, अगर यह काम करता है तो मुझे बताएं। दिलचस्प। – hasan83

+0

मैं सेलविल्लडिस्प्ले टेबलव्यू प्रतिनिधि विधि के साथ केवल सेल पैरामीटर के प्रकार को बदलकर ऐसा करने का प्रयास करता हूं। यह काम नहीं करता है। विधि को ओवरराइडिंग के रूप में नहीं माना जाता है। शायद उन्होंने इसे इस तरह लागू नहीं किया। – hasan83

+0

मेरी मदद करने की कोशिश करने के लिए धन्यवाद। यह सही दिशा में एक प्रयास हो सकता है। हालांकि, यह डेटासोर्स के मेरे उप-वर्गों पर शिकायत करता है। के रूप में आप एक सामान्य पैरामीटर के रूप में CellDataSetupable कहा, मैं इनपुट को यह करने के लिए कुछ बात है, लेकिन यह पैदा करता है एक 'एक CellDataSetupable एक ठोस प्रकार प्रोटोकॉल CellDataSetupable के अनुरूप के रूप में उपयोग करते हुए supported' नहीं है। अधिक कोड के लिए उपरोक्त प्रश्न में "संपादित करें 1" देखें। – Sunkas

0

जब आप DataSource उपयोग कर रहे हैं, तो आप ठोस प्रकार प्रदान करते हैं कि साथ DataSource काम करता है। तो,

class HomeTableViewDataSource: DataSource<HomeViewController, HomeViewTableViewCellData, HomeViewModel, CellDataSetupable> { 

वास्तव में

class HomeTableViewDataSource: DataSource<HomeViewController, HomeViewTableViewCellData, HomeViewModel, HomeTableViewCell> { 

जहां HomeTableViewCell एक ठोस UITableViewCell उपवर्ग कि CellDataSetupable के अनुरूप है (जैसे BlurbTableViewCell या TransactionTableViewCell) है होना चाहिए। यह तब ठीक काम करेगा।

यहाँ एक सरल सामान्य TableViewDataSource उदाहरण है कि काम करता है और शायद एक छोटे से समझना आसान है।

जेनेरिक प्रकार:

import UIKit 

protocol CellDataProtocol { 
    var cellIdentifier: String { get } 
} 

protocol ConfigurableCell { 
    associatedtype Data: CellDataProtocol 
    func configure(with data: Data) 
} 

class DataSource<CellData: CellDataProtocol, Cell: ConfigurableCell>: NSObject, UITableViewDataSource where Cell.Data == CellData { 

    var data: [CellData]! 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
     return data.count 
    } 

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cellData = data[indexPath.row] 
     let cell = tableView.dequeueReusableCell(withIdentifier: cellData.cellIdentifier, for: indexPath) 
     if let cell = cell as? Cell { 
      cell.configure(with: cellData) 
     } 
     return cell 
    } 
} 

कंक्रीट वर्गों है कि इसके बाद के संस्करण कोड के शीर्ष पर बनाया जाता है:

class DataObject: CellDataProtocol { 
    var cellIdentifier: String { 
     return "Identifier" 
    } 

    // an additional property of the class 
    var number: Int { 
     return 5 
    } 
} 

class TableViewCell: UITableViewCell, ConfigurableCell { 
    func configure(with data: DataObject) { 
     // configure cell UI with data 

     // properties can be used here 
     // since the exact type is known 
     self.textLabel?.text = "\(data.number)" 
    } 
} 

let dataSource = DataSource<DataObject, TableViewCell>() 

class ConcreteDataSource: DataSource<DataObject, TableViewCell> { 
    // additional functionality 
} 

संपादित करें: आप उपवर्ग भी कोशिकाओं के विभिन्न प्रकारों के साथ काम कर सकते हैं अगर आप चाहते हैं।

class SubDataSource<Cell: ConfigurableCell>: DataSource<DataObject, Cell> where Cell.Data == DataObject { 
    // additional functionality 
} 

let d = SubDataSource<TableViewCell>() 

आशा है कि इससे मदद मिलती है! सौभाग्य!

+0

आपके उत्तर के लिए धन्यवाद। हालांकि, मैं 'होमटेबल व्यूसेल' को कंक्रीट के रूप में नहीं जोड़ सकता क्योंकि डेटासोर्स के विभिन्न प्रकार हो सकते हैं। यह काफी सामान्य है कि 'UITableView' में' UITableViewCell 'के विभिन्न प्रकार के सेल और उप-वर्ग हैं। मैं खुद को इन प्रकारों में से किसी एक को सीमित नहीं करना चाहता हूं। मेरी समस्या यह थी कि मैं इन कोशिकाओं के लिए प्रोटोकॉल का उपयोग करना चाहता हूं ताकि मैं जांच सकूं कि "सेटअप करने योग्य" हैं या फिर सेटअप विधि को कॉल करें। यह काफी आसान होगा। यह "HomeTableViewCell" और "Blurb ..." के लिए एक आधार वर्ग के साथ व्याख्या करने योग्य है, लेकिन फिर मैं मैं के साथ मानकों कास्ट करने के लिए नहीं करना चाहती – Sunkas

+0

हाँ, मैं समझता हूँ की है। मेरा जवाब नेट मैन ने सुझाव दिया है कि आपने संपादित 1 में वर्णित समस्या को हल करने के तरीके के बारे में बताया है। एक बार फिर, डेटा सॉस घोषणा में आपको एक सामान्य पैरामीटर 'सेल: सेलडाटासेटअप' का उपयोग करना चाहिए, लेकिन जब आप कक्षा को तुरंत चालू करते हैं एक ठोस वस्तु, आप एक ठोस 'UITableViewCell' उपclass का उपयोग करें। या, यदि आप एक उप-वर्ग को विभिन्न प्रकार के कोशिकाओं के साथ काम करना चाहते हैं, तो आप इसे सामान्य भी बना सकते हैं। संपादन देखें। – timaktimak

+0

मैंने अपने प्रश्न में संक्षेप में उल्लेख किया है कि UIView ऑब्जेक्ट्स का जेनेरिक सबक्लास बनाना इंटरफ़ेस बिल्डर में समर्थित नहीं है। अब मैंने इसे हाइलाइट करने के लिए 'संपादित करें 2' जोड़ा, साथ ही किसी अन्य SO प्रश्न के लिंक के साथ।मैंने बिना किसी सफलता के एक सामान्य UITableViewCell-class का ठोस सबक्लास बनाने की कोशिश की है। – Sunkas