NSArchiver
पुनः ओएस एक्स 10.2 के बाद से हटा दिया गया है, और iOSउपवर्गीकरण NSCoder, NSArchiver
दूसरी ओर पर AFAIK उपलब्ध नहीं है, NSKeyedArchiver
गति & संक्षिप्तता ओर से कमी है (some users रिपोर्ट 100 से अधिक जाना जाता है NSKeyedArchiver
और NSArchiver
के बीच प्रदर्शन प्रदर्शन अंतर)। जिन वस्तुओं को मैं संग्रहित करना चाहता हूं वे मुख्य रूप से NSObject
उप-वर्ग हैं जिनमें NSNumber
हैं, और ऑब्जेक्ट्स जिनमें आदिम प्रकार हैं (मुख्य रूप से double
)। मुझे विश्वास नहीं है कि ओवरहेड कुंजी संग्रह का तात्पर्य यह है कि इसका लायक है।
इसलिए मैंने NSArchiver
की शैली में एक सीरियल कोडर बनाने के लिए आईओएस पर NSCoder
को उपclass करने का निर्णय लिया।
मैं समझता हूं कि कुंजी वाले अभिलेखागार आसानी से कहां आ सकते हैं: पिछड़ा आगे संगतता और अन्य niceties, और शायद यही है कि मैं इसका उपयोग कर समाप्त करूँगा, लेकिन मुझे यह जानकर उत्सुकता होगी कि मैं धारावाहिक संग्रह के साथ किस तरह के प्रदर्शन प्राप्त कर सकता हूं । और स्पष्ट रूप से, मुझे लगता है कि मैं ऐसा करके बहुत सी चीजें सीख सकता हूं। तो मैं वैकल्पिक समाधान में रूचि रखता हूं;
मैं Cocotron के स्रोतों से प्रेरित किया गया है, एक खुला स्रोत NSArchiver
TLDR: मैं NSArchiver
के पुनर्निर्माण के लिए मैं एआरसी का उपयोग कर रहा है, के लिए संकलन NSCoder
उपवर्ग करना चाहते हैं आईओएस 6 & 7, और अब के लिए 32 बिट सिस्टम मानते हैं।
मैं अब के लिए वस्तुओं या तार को संदर्भित में दिलचस्पी नहीं है, मैं सिर्फ उपयोग कर रहा हूँ एक NSHashTable
(weakObjectsHashTable
) वर्ग के नाम को रोकने के लिए दोहराया जा करने के लिए: कक्षाएं पहली बार उनका सामना कर रहे हैं वर्णित किया जाएगा, और फिर संदर्भ से संबोधित किया जाता ।
मैं एक NSMutableData
उपयोग कर रहा हूँ संग्रह का निर्माण करने की:
@interface Archiver {
NSMutableData *_data;
void *_bytes;
size_t _position;
NSHashTable *_classes;
}
@end
बुनियादी तरीके हैं:
-(void)_expandBuffer:(NSUInteger)length
{
[_data increaseLengthBy:length];
_bytes = _data.mutableBytes;
}
-(void)_appendBytes:(const void *)data length:(NSUInteger)length
{
[self _expandBuffer:length];
memcpy(_bytes+_position, data, length);
_position += length;
}
मैं _appendBytes:length:
उपयोग कर रहा हूँ आदिम प्रकार डंप करने के लिए इस तरह के रूप int
, char
, float
, double
... आदि कुछ भी दिलचस्प नहीं है।
सी शैली तार इस उतना ही अरुचिकर विधि का उपयोग कर फेंक दिया जाता है:
-(void)_appendCString:(const char*)cString
{
NSUInteger length = strlen(cString);
[self _appendBytes:cString length:length+1];
}
और अंत में, संग्रह कक्षा की जानकारी और वस्तुओं:
-(void)_appendReference:(id)reference {
[self _appendBytes:&reference length:4];
}
-(void)_appendClass:(Class)class
{
// NSObject class is always represented by nil by convention
if (class == [NSObject class]) {
[self _appendReference:nil];
return;
}
// Append reference to class
[self _appendReference:class];
// And append class name if this is the first time it is encountered
if (![_classes containsObject:class])
{
[_classes addObject:class];
[self _appendCString:[NSStringFromClass(class) cStringUsingEncoding:NSASCIIStringEncoding]];
}
}
-(void)_appendObject:(const id)object
{
// References are saved
// Although we don't handle relationships between objects *yet* (we could do it the exact same way we do for classes)
// at least it is useful to determine whether object was nil or not
[self _appendReference:object];
if (object==nil)
return;
[self _appendClass:[object classForCoder]];
[object encodeWithCoder:self];
}
मेरी वस्तुओं की encodeWithCoder:
तरीकों कि सभी तरह दिखते हैं, कुछ भी नहीं फैंसी:
[aCoder encodeValueOfObjCType:@encode(double) at:&_someDoubleMember];
[aCoder encodeObject:_someCustomClassInstanceMember];
[aCoder encodeObject:_someMutableArrayMember];
डिकोडिंग काफी समान तरीके से चला जाता है; अनारक में NSMapTable
कक्षाएं हैं जो पहले से ही जानते हैं और कक्षा संदर्भ के नाम की तलाश में हैं जो इसे नहीं जानते हैं।
-(id)_extractReference
{
id reference;
[self _extractBytesTo:&reference length:4];
return reference;
}
-(Class)_extractClass
{
// Lookup class reference
id classReference = [self _extractReference];
// NSObject is always nil
if (classReference==nil)
return [NSObject class];
// Do we already know that one ?
if (![_classes objectForKey:classReference])
{
// If not, then the name should follow
char *classCName = [self _extractCString];
NSString *className = [NSString stringWithCString:classCName encoding:NSASCIIStringEncoding];
free(classCName);
Class class = NSClassFromString(className);
[_classes setObject:class forKey:classReference];
}
return [_classes objectForKey:classReference];
}
-(id)_extractObject
{
id objectReference = [self _extractReference];
if (!objectReference)
{
return nil;
}
Class objectClass = [self _extractClass];
id object = [[objectClass alloc] initWithCoder:self];
return object;
}
:
@interface Unarchiver(){
NSData *_data;
const void *_bytes;
NSMapTable *_classes;
}
@end
मैं
-(void)_extractBytesTo:(void*)data length:(NSUInteger)length
और
-(char*)_extractCString
रोचक सामग्री शायद वस्तु डिकोडिंग कोड में है की बारीकियों के साथ आप बोर नहीं होंगे और अंत में, केंद्रीय विधि (मैं डब्ल्यू यदि समस्या यहीं कहीं है आश्चर्य नहीं ould)
-(void)decodeValueOfObjCType:(const char *)type at:(void *)data
{
switch(*type){
/* snip, snip */
case '@':
*(id __strong *) data = [self _extractObject];
break;
}
}
initWithCoder:
विधि encodeWithCoder:
के पिछले टुकड़ा करने के लिए इसी है कि
if (self = [super init]) {
// Order is important
[aDecoder decodeValueOfObjCType:@encode(double) at:& _someDoubleMember];
_someCustomClassInstanceMember = [aDecoder decodeObject];
_someMutableArrayMember = [aDecoder decodeObject];
}
return self;
मेरे decodeObject
कार्यान्वयन की तरह कुछ जाना होगा बिल्कुल _extractObject
है।
अब, यह सब अच्छा और अच्छी तरह से काम करना चाहिए। और तथ्य की बात के रूप में; मैं अपनी कुछ वस्तुओं को संग्रहित/अनारक्षित करने में सक्षम हूं। अभिलेखागार ठीक दिखते हैं, इस हद तक कि मैं उन्हें हेक्स संपादक में निरीक्षण करने के लिए तैयार हूं, और मैं double
एस वाले किसी अन्य वर्ग के NSMutableArray
एस वाले कुछ कस्टम वर्गों को अनारक्षित करने में सक्षम हूं।
लेकिन किसी कारण से, अगर मैं एक की NSNumber
NSMutableArray
युक्त मेरी वस्तु में से एक संग्रह से निकालने की कोशिश करते हैं, मैं इस समस्या में पड़:
malloc: *** error for object 0xc112cc: pointer being freed was not allocated
में NSNumber
प्रति एक लाइन होने के लिए वहाँ लगता है सरणी, और पता 0xc112cc
प्रत्येक पंक्ति के लिए समान है। malloc_error_break
में ब्रेकपॉइंट डालने से मुझे पता चलता है कि त्रुटियां -[NSPlaceholderNumber initWithCoder:]
से हैं (मेरी _extractObject
विधि से बुलाया गया है)।
क्या यह एआरसी के उपयोग से जुड़ी कोई समस्या है? मैं क्या खो रहा हूँ ?
क्या आप एक न्यूनतम initWithCoder साझा कर सकते हैं: कार्यान्वयन? – James
मैंने अपनी पोस्ट को नमूना 'initWithCoder: 'कार्यान्वयन के साथ अपडेट किया। यह काफी सरल है। – Olotiar
में टैग पॉइंटर के साथ कुछ करने के लिए हो सकता है, चेकिंग आपके द्वारा संग्रहीत वास्तविक मूल्य '0xc112cc' है? –