2011-12-14 10 views
8

मैं ISA Switching इसलिए की तरह साथ Using a UITableView subclass with a UITableViewController जवाब देने के लिए करने की कोशिश की:उद्देश्य-सी: किसी ऑब्जेक्ट की कक्षा को रनटाइम पर कैसे बदला जाए?

self.tableView->isa = [MyTableView class]; 

लेकिन, मुझे संकलन त्रुटि मिलती है: Instance variable 'isa' is protected.

वहाँ एक रास्ता यह चारों ओर पाने के लिए है? और, यदि हां, तो क्या यह सुरक्षित है?

मैं पूछ रहा हूं क्योंकि @AmberStar's answer to that question थोड़ा दोषपूर्ण लगता है। (मेरी टिप्पणी देखें।)

उत्तर

22

यदि आपकी टेबलव्यू कक्षा किसी भी संग्रहण प्रदान करती है तो यह टूट जाएगी। मैं जिस मार्ग पर जा रहा हूं उसकी अनुशंसा नहीं करता हूं। लेकिन सही विधि object_setClass(tableView, [MyTableView class]) का उपयोग करना होगा।

कृपया सुनिश्चित करें कि यह वास्तव में आप चाहते हैं।

यहां एक छोटा कोड-नमूना दिखा रहा है कि यह एक भयानक विचार है।

#import <objc/runtime.h> 

@interface BaseClass : NSObject 
{ 
    int a; 
    int b; 
} 
@end 

@implementation BaseClass 

@end 

@interface PlainSubclass : BaseClass 
@end 

@implementation PlainSubclass 
@end 

@interface StorageSubclass : BaseClass 
{ 
@public 
    int c; 
} 
@end 

@implementation StorageSubclass 
@end 



int main(int argc, char *argv[]) 
{ 
    BaseClass *base = [[BaseClass alloc] init]; 
    int * random = (int*)malloc(sizeof(int)); 
    NSLog(@"%@", base); 

    object_setClass(base, [PlainSubclass class]); 
    NSLog(@"%@", base); 

    object_setClass(base, [StorageSubclass class]); 
    NSLog(@"%@", base); 
    StorageSubclass *storage = (id)base; 
    storage->c = 0xDEADBEEF; 
    NSLog(@"%X == %X", storage->c, *random); 
} 

और आउटपुट

2011-12-14 16:52:54.886 Test[55081:707] <BaseClass: 0x100114140> 
2011-12-14 16:52:54.889 Test[55081:707] <PlainSubclass: 0x100114140> 
2011-12-14 16:52:54.890 Test[55081:707] <StorageSubclass: 0x100114140> 
2011-12-14 16:52:54.890 Test[55081:707] DEADBEEF == DEADBEEF 

आप storage->c को लिखने देख सकते हैं स्मृति उदाहरण के लिए आवंटित बाहर लिखा था, और ब्लॉक में मैं यादृच्छिक के लिए आवंटित। अगर वह एक और वस्तु थी, तो आपने अभी अपना isa पॉइंटर नष्ट कर दिया था।

+0

कूल धन्यवाद। लेकिन, 'UITableViewController' में 'self.tableView' को' UITableView' के कस्टम सबक्लास के नए उदाहरण में सेट करना सुरक्षित है? – ma11hew28

+1

@ जोशुआ वेनबर्ग कहते हैं, क्या आप जानते हैं कि इसका उपयोग करना बुरा होगा [सहयोगी संदर्भ] (http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocAssociativeReferences.html) मुझे पता है कि श्रेणियों के साथ उपयोग करना सुरक्षित है (इसे कई बार इस्तेमाल किया जाता है) लेकिन अगर सबक्लास को एक और चर की आवश्यकता है, तो मुझे लगता है कि यह चाल करेगा ... –

+1

मैं उन्हें हर समय, काफी आसान उपयोग करता हूं। –

5

सुरक्षित तरीका एक नया उदाहरण बनाना है।

स्वैपिंग isa सुरक्षित नहीं है - आपको पता नहीं है कि कक्षा का मेमोरी लेआउट क्या है या भविष्य में यह क्या होगा। विरासत ग्राफ को भी ऊपर ले जाना वास्तव में सुरक्षित नहीं है क्योंकि ऑब्जेक्ट्स की शुरुआत और विनाश सही ढंग से नहीं किया जाएगा - आपकी ऑब्जेक्ट को संभावित रूप से अमान्य स्थिति में छोड़कर (जो आपका पूरा प्रोग्राम नीचे ला सकता है)।

+0

कूल, धन्यवाद। लेकिन, 'UITableViewController' में 'self.tableView' को' UITableView' के कस्टम सबक्लास के नए उदाहरण में सेट करना सुरक्षित है? – ma11hew28

+2

@ मैट हां, आप 'UITableView' को उपclass कर सकते हैं, लेकिन आपको तालिका के प्रकार को बदलने की प्रक्रिया में तालिका को पुनर्निर्माण करना होगा। अधिक जटिल परिदृश्यों में, आप किसी ऑब्जेक्ट का पक्ष ले सकते हैं जिसे अधिक आसानी से बदला जा सकता है (उदाहरण के लिए एक ऑब्जेक्ट जो उपस्थिति को स्टाइल करता है या डेटा को अलग-अलग प्रस्तुत करता है)। – justin

संबंधित मुद्दे