1

My application is designed to view the catalog with products. All data received from the server (xml) are parsed in NSDictionary. So NSDictionary contains about 5000 items. Reading a dictionary using NSKeyedUnarchiver takes 24 seconds. It is unacceptable.

I don't need forward and backward compatible, because after app updating catalog will be downloaded again and old data will be deleted.

My dictionary isn't property list, so writeToFile isn't working.

NSArchiever(NSUnarchiever) would be a great solution to the problem, but it replaced by NSKeyedArchiver.

Any ideas? Maybe I should use CoreData but I don't know anything about it.

Thanks

maxibystro
  • 25
  • 1
  • 7

2 Answers2

0

Have you tried saving it as a JSON formatted file? NSJSONSerialization would help you go back and forth between file data and a NSDictionary. It was added in iOS5.

https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSJSONSerialization_Class/Reference/Reference.html

Let me know if it performs well enough for you.

Dylan Bettermann
  • 753
  • 8
  • 14
  • Thank you for advice. But keys of my dictionary are instances of NSNumber (it is product ID) and it can't be converted to JSON. – maxibystro Sep 05 '13 at 15:37
  • Have you tried by storing the keys as string representation of those numbers? It may work if you do not really need them to be numbers. – veducm Sep 05 '13 at 17:28
  • That's what I'm doing right now) But maybe this is the wrong practice. – maxibystro Sep 06 '13 at 07:10
  • My dictionary contains custom classes so I can't directly use NSJSONSerialization. But the solution is found. – maxibystro Sep 15 '13 at 19:06
-1

My solution is to use custom serialization. In the end, all data is presented as property list. All my custom classes that should be serialized support protocol PropertyListCoder (like NSCoder):

@protocol PropertyListCoder

- (id)encodeToPropertyListObject;
- (id)initWithPropertyListObject:(id)object;

@end

For example, serialization for class Product:

@interface Product : NamedObject <NSCoding, PropertyListCoder> {
}

@property (nonatomic, readwrite) uint               mId;
@property (nonatomic, retain) NSString              *mDesc;
@property (nonatomic, retain) NSString              *mIcon;

@property (nonatomic, retain) NSString              *mCode;
@property (nonatomic, readwrite) uint               mSort;
@property (nonatomic, retain) NSMutableArray        *mArrOfText;

@property (nonatomic, readonly) NSMutableArray      *mProperties;
@property (nonatomic, retain) NSString              *mImage;
@property (nonatomic, readwrite) float              mPrice;
@property (nonatomic, readwrite) float              mDiscPrice;

@end

And here are methods of the protocol:

- (id)encodeToPropertyListObject {
id superPropList = [super encodeToPropertyListObject];
NSNumber* idNumber = [[NSNumber alloc] initWithInt:mId];
NSNumber* sortNumber = [[NSNumber alloc] initWithInt:mSort];
NSMutableArray* arrOfTextPropList = [[NSMutableArray alloc] init];
for (NSAttString* str in self.mArrOfText) {
    [arrOfTextPropList addObject:[str encodeToPropertyListObject]];
}
NSMutableArray* propPropList = [[NSMutableArray alloc] init];
for (Property* prop in self.mProperties) {
    [propPropList addObject:[prop encodeToPropertyListObject]];
}
NSNumber* priceNumber = [[NSNumber alloc] initWithInt:mPrice];
NSNumber* discPriceNumber = [[NSNumber alloc] initWithInt:mDiscPrice];

NSArray* res = [NSArray arrayWithObjects:superPropList, idNumber, [Utility notNilStringWithString:mDesc], [Utility notNilStringWithString:mIcon], [Utility notNilStringWithString:mCode], sortNumber, arrOfTextPropList, propPropList, [Utility notNilStringWithString:mImage], priceNumber, discPriceNumber, nil];

[idNumber release];
[sortNumber release];
[arrOfTextPropList release];
[propPropList release];
[priceNumber release];
[discPriceNumber release];

return res;
}

- (id)initWithPropertyListObject:(id)object {
NSArray* arr = (NSArray*)object;
self = [super initWithPropertyListObject:[arr objectAtIndex:0]];
if (self) {
    mId = [[arr objectAtIndex:1] intValue];
    mDesc = [[arr objectAtIndex:2] retain];
    mIcon = [[arr objectAtIndex:3] retain];
    mCode = [[arr objectAtIndex:4] retain];
    mSort = [[arr objectAtIndex:5] intValue];
    mArrOfText = [[NSMutableArray alloc] init];
    mProperties = [[NSMutableArray alloc] init];

    for (id subObj in (NSArray*)[arr objectAtIndex:6]) {
        NSAttString* str = [[NSAttString alloc] initWithPropertyListObject:subObj];
        [mArrOfText addObject:str];
        [str release];
    }
    for (id subObj in (NSArray*)[arr objectAtIndex:7]) {
        Property* prop = [[Property alloc] initWithPropertyListObject:subObj];
        [mProperties addObject:prop];
        [prop release];
    }
    mImage = [[arr objectAtIndex:8] retain];
    mPrice = [[arr objectAtIndex:9] floatValue];
    mDiscPrice = [[arr objectAtIndex:10] floatValue];
}
return self;
}

Root object could be NSDictionary or NSArray. Then for read / write I use NSPropertyListSerialization with binary format. And now reading the dictionary takes 3.5 seconds!

maxibystro
  • 25
  • 1
  • 7