मैं उपयोग करने से बचता हूं UITableViewController
, क्योंकि यह एक ही वस्तु में बहुत सारी जिम्मेदारियां डालता है। इसलिए मैं UIViewController
उप-स्रोत को डेटा स्रोत और प्रतिनिधि से अलग करता हूं । व्यू कंट्रोलर की जिम्मेदारी टेबल व्यू तैयार करना, डेटा के साथ डेटा स्रोत बनाना और उन चीजों को एक साथ हुक करना है। जिस तरह से टेबलव्यू का प्रतिनिधित्व किया जाता है उसे व्यू कंट्रोलर को बदले बिना बदला जा सकता है, और वास्तव में एक ही व्यू कंट्रोलर का उपयोग कई डेटा स्रोतों के लिए किया जा सकता है जो सभी इस पैटर्न का पालन करते हैं। इसी तरह, ऐप वर्कफ़्लो को बदलने का मतलब है कि टेबल पर क्या होता है, इसकी चिंता किए बिना व्यू कंट्रोलर में बदलाव।
मैंने अलग-अलग ऑब्जेक्ट्स में UITableViewDataSource
और UITableViewDelegate
प्रोटोकॉल को अलग करने की कोशिश की है , लेकिन यह आमतौर पर एक गलत विभाजन के रूप में समाप्त होता है, क्योंकि प्रतिनिधि पर लगभग हर विधि डेटा स्रोत में खोदने की आवश्यकता होती है (उदाहरण के लिए चयन पर, प्रतिनिधि को यह जानने की जरूरत है कि ऑब्जेक्ट का प्रतिनिधित्व किस वस्तु द्वारा किया जाता है। चयनित पंक्ति)। तो मैं एक ही वस्तु के साथ समाप्त होता है जो डेटासोर्स और डेलिगेट दोनों है। यह ऑब्जेक्ट हमेशा एक विधि प्रदान करता है -(id)tableView: (UITableView *)tableView representedObjectAtIndexPath: (NSIndexPath *)indexPath
जो डेटा स्रोत और प्रतिनिधि पहलुओं दोनों को यह जानने की आवश्यकता है कि वे क्या काम कर रहे हैं।
यह मेरा "स्तर 0" चिंताओं का पृथक्करण है। यदि मुझे एक ही तालिका दृश्य में विभिन्न प्रकार की वस्तुओं का प्रतिनिधित्व करना है, तो स्तर 1 व्यस्त हो जाता है। एक उदाहरण के रूप में, कल्पना करें कि आपको संपर्क ऐप लिखना था - एक ही संपर्क के लिए, आपके पास पंक्तियाँ हो सकती हैं जो फ़ोन नंबर का प्रतिनिधित्व करती हैं, अन्य पंक्तियों का प्रतिनिधित्व करती हैं, दूसरों को ईमेल पते का प्रतिनिधित्व करती हैं, और इसी तरह। मैं इस दृष्टिकोण से बचना चाहता हूं:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
id object = [self tableView: tableView representedObjectAtIndexPath: indexPath];
if ([object isKindOfClass: [PhoneNumber class]]) {
//configure phone number cell
}
else if …
}
दो समाधानों ने खुद को अब तक प्रस्तुत किया है। एक गतिशील रूप से चयनकर्ता का निर्माण करना है:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
id object = [self tableView: tableView representedObjectAtIndexPath: indexPath];
NSString *cellSelectorName = [NSString stringWithFormat: @"tableView:cellFor%@AtIndexPath:", [object class]];
SEL cellSelector = NSSelectorFromString(cellSelectorName);
return [self performSelector: cellSelector withObject: tableView withObject: object];
}
- (UITableViewCell *)tableView: (UITableView *)tableView cellForPhoneNumberAtIndexPath: (NSIndexPath *)indexPath {
// configure phone number cell
}
इस दृष्टिकोण में, आपको if()
एक नए प्रकार का समर्थन करने के लिए महाकाव्य पेड़ को संपादित करने की आवश्यकता नहीं है - बस उस विधि को जोड़ें जो नए वर्ग का समर्थन करता है। यह एक महान दृष्टिकोण है यदि यह तालिका दृश्य एकमात्र है जिसे इन वस्तुओं का प्रतिनिधित्व करने की आवश्यकता है, या उन्हें एक विशेष तरीके से प्रस्तुत करने की आवश्यकता है। यदि समान ऑब्जेक्ट्स को अलग-अलग डेटा स्रोतों के साथ अलग-अलग तालिकाओं में दर्शाया जाएगा, तो यह दृष्टिकोण टूट जाता है क्योंकि सेल निर्माण विधियों को डेटा स्रोतों में साझा करने की आवश्यकता होती है - आप एक सामान्य सुपरक्लास को परिभाषित कर सकते हैं जो इन विधियों को प्रदान करता है, या आप ऐसा कर सकते हैं:
@interface PhoneNumber (TableViewRepresentation)
- (UITableViewCell *)tableView: (UITableView *)tableView representationAsCellForRowAtIndexPath: (NSIndexPath *)indexPath;
@end
@interface Address (TableViewRepresentation)
//more of the same…
@end
फिर अपने डेटा स्रोत वर्ग में:
- (UITableViewCell *)tableView: (UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
id object = [self tableView: tableView representedObjectAtIndexPath: indexPath];
return [object tableView: tableView representationAsCellForRowAtIndexPath: indexPath];
}
इसका मतलब यह है कि किसी भी डेटा स्रोत को फोन नंबर, पते आदि को प्रदर्शित करने की आवश्यकता है जो टेबल व्यू सेल के लिए किसी भी वस्तु का प्रतिनिधित्व कर सकता है। डेटा स्रोत को अब प्रदर्शित होने वाली वस्तु के बारे में कुछ भी जानने की आवश्यकता नहीं है।
"लेकिन रुकिए," मैं एक काल्पनिक अंतःसंबंधक विशेषण सुनता हूं, "जो एमवीसी को नहीं तोड़ता ? क्या आप एक मॉडल वर्ग में विवरण नहीं डाल रहे हैं?"
नहीं, यह MVC को नहीं तोड़ता है। आप इस मामले में श्रेणियों के बारे में सोच सकते हैं कि डेकोरेटर का कार्यान्वयन ; तो PhoneNumber
एक मॉडल वर्ग है, लेकिन PhoneNumber(TableViewRepresentation)
एक दृश्य श्रेणी है। डेटा स्रोत (एक नियंत्रक वस्तु) मॉडल और दृश्य के बीच मध्यस्थता करता है, इसलिए एमवीसी वास्तुकला अभी भी रखती है।
आप एप्पल के ढांचे में सजावट के रूप में श्रेणियों के इस उपयोग को देख सकते हैं। NSAttributedString
एक मॉडल वर्ग है, जिसमें कुछ पाठ और विशेषताएँ होती हैं। AppKit प्रदान करता है NSAttributedString(AppKitAdditions)
और UIKit NSAttributedString(NSStringDrawing)
, सज्जाकार श्रेणियां प्रदान करता है जो इन मॉडल वर्गों के लिए ड्राइंग व्यवहार जोड़ते हैं।