2012-01-20 19 views
6

करने का आसान तरीका मेरे पास कई ऑब्जेक्ट्स हैं जिन्हें मैं ऑफ़लाइन उपयोग के लिए सहेजना चाहता हूं। वर्तमान में मैं ऑफ़लाइन उपलब्ध होने के लिए ऑब्जेक्ट्स और कोड किए गए डेटा के लिए एनएससीओडर अनुपालन कक्षाओं का उपयोग करता हूं।एनएससीओडर सक्षम वर्ग

तो ज में मैं वस्तुओं परिचय:

- (id) initWithCoder: (NSCoder *)coder { 
    if (self = [super init]) { 
     [self setMyObject: [coder decodeObjectForKey:@"myObject"]]; 
    } 
} 

- (void) encodeWithCoder: (NSCoder *)coder { 
    [coder encodeObject: myObject forKey:@"myObject"]; 
} 

तो वर्ग गेटर और सेटर के साथ सिर्फ डमी भंडारण है:

@interface MyClass : NSObject<NSCoding>{ 
NSNumber* myObject;} 
@property(nonatomic,retain) NSNumber* myObject; 

और मीटर में मैं inits बनाते हैं। यहां डीकोड/एन्कोड करने का कोई बेहतर तरीका है। क्या मैं एन्कोड और डीकोड के लिए किसी भी तरह @ गतिशील या कुंजी-मूल्य कोडिंग का उपयोग कर सकता हूं? मूल रूप से मैं कक्षा में सभी चर फ़ाइल को सहेजने के लिए सहेजना चाहता हूं और प्रोग्राम शुरू होने पर ऑब्जेक्ट पर वापस आना चाहता हूं। यह दृष्टिकोण काम करता है, लेकिन सभी वर्गों को बनाने में समय और प्रयास लगता है।

उत्तर

43

हां, आप इसे स्वचालित रूप से कर सकते हैं। सबसे पहले अपने वर्ग में इन आयात:

- (NSArray *)propertyKeys 
{ 
    NSMutableArray *array = [NSMutableArray array]; 
    Class class = [self class]; 
    while (class != [NSObject class]) 
    { 
     unsigned int propertyCount; 
     objc_property_t *properties = class_copyPropertyList(class, &propertyCount); 
     for (int i = 0; i < propertyCount; i++) 
     { 
      //get property 
      objc_property_t property = properties[i]; 
      const char *propertyName = property_getName(property); 
      NSString *key = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]; 

      //check if read-only 
      BOOL readonly = NO; 
      const char *attributes = property_getAttributes(property); 
      NSString *encoding = [NSString stringWithCString:attributes encoding:NSUTF8StringEncoding]; 
      if ([[encoding componentsSeparatedByString:@","] containsObject:@"R"]) 
      { 
       readonly = YES; 

       //see if there is a backing ivar with a KVC-compliant name 
       NSRange iVarRange = [encoding rangeOfString:@",V"]; 
       if (iVarRange.location != NSNotFound) 
       { 
        NSString *iVarName = [encoding substringFromIndex:iVarRange.location + 2]; 
        if ([iVarName isEqualToString:key] || 
         [iVarName isEqualToString:[@"_" stringByAppendingString:key]]) 
        { 
         //setValue:forKey: will still work 
         readonly = NO; 
        } 
       } 
      } 

      if (!readonly) 
      { 
       //exclude read-only properties 
       [array addObject:key]; 
      } 
     } 
     free(properties); 
     class = [class superclass]; 
    } 
    return array; 
} 

तो यहाँ NSCoder तरीके हैं::

- (id)initWithCoder:(NSCoder *)aDecoder 
{ 
    if ((self = [self init])) 
    { 
     for (NSString *key in [self propertyKeys]) 
     { 
      id value = [aDecoder decodeObjectForKey:key]; 
      [self setValue:value forKey:key]; 
     } 
    } 
    return self; 
} 

- (void)encodeWithCoder:(NSCoder *)aCoder 
{ 
    for (NSString *key in [self propertyKeys]) 
    { 
     id value = [self valueForKey:key]; 
     [aCoder encodeObject:value forKey:key]; 
    } 
} 

#import <objc/runtime.h> 
#import <objc/message.h> 

अब इस विधि है, जो निम्न स्तर विधियों का उपयोग करेगा संपत्ति नाम प्राप्त करने के लिए जोड़

आपको इसके साथ थोड़ा सावधान रहना होगा।

  1. यह गुण है कि नंबर, bools, वस्तुओं, आदि कर रहे हैं के लिए काम करेंगे, लेकिन कस्टम structs काम नहीं करेगा: वहाँ निम्न चेतावनियां हैं। साथ ही, यदि आपकी कक्षा में से कोई भी गुण ऐसी वस्तुएं हैं जो विषयों को एनएससीओडी का समर्थन नहीं करते हैं, तो यह काम नहीं करेगा।

  2. यह केवल संश्लेषित गुणों के साथ काम करेगा, न कि इवर।

आप इसे एन्कोडिंग, या अधिक शान से एक समस्या को संभालने के लिए setValueForUndefinedKey विधि अधिभावी से पहले encodeWithCoder में एक मूल्य के प्रकार की जाँच करके त्रुटि हैंडलिंग जोड़ सकते हैं।

अद्यतन:

मैं एक पुस्तकालय में इन तरीकों की समाप्ति के है: https://github.com/nicklockwood/AutoCoding - पुस्तकालय इसलिए किसी भी वर्ग को बचाया या लोड किया जा सकता NSObject पर एक वर्ग के रूप में इन तरीकों को लागू करता है, और यह भी विरासत में मिला कोडिंग के लिए समर्थन जोड़ता गुण, जो मेरा मूल उत्तर संभाल नहीं करता है।

अद्यतन 2:

मैं इस सवाल का जवाब सही ढंग से विरासत में मिला के साथ सौदा और केवल पढ़ने के लिए गुण अपडेट किया है।

+0

महान उत्तर के लिए धन्यवाद, यह मेरे उद्देश्य के लिए बिल्कुल सही है। मैं आपको वोट दूंगा, लेकिन मेरे पास पर्याप्त प्रतिष्ठा नहीं है .. – MapaX

+0

कोड में छोटी मेमोरी लीक है। आपको जोड़ने की जरूरत है: मुफ्त (गुण); संपत्ति के लिए विधि विधि। – MapaX

+0

अच्छी कॉल - मैंने इसे ठीक कर दिया है। –

0

लाइब्रेरी https://github.com/nicklockwood/AutoCoding का प्रदर्शन अच्छा नहीं है क्योंकि यह हर बार class_copyPropertyList का उपयोग करके प्रतिबिंब करता है, और ऐसा लगता है कि यह कुछ structs का समर्थन नहीं करता है।

https://github.com/flexme/DYCoding चेक करें, यह पूर्व-संकलित कोड जितना तेज़ होना चाहिए, और यह विभिन्न संपत्ति प्रकारों का समर्थन करता है।