0

I'm trying to implement persistence for a simple data model of an iOS app. It's kind of a database, but with a small amount of data (200-500 entries). I think core data is no option here.

The data model looks somehow like this (currently I use NSDictionary with NSArray):

// Note: NSStrings and NSNumbers are simplified for readability (no @)
@{ "Companys" : @[
          @{ "ID"           : 1,
             "Company name" : "ABC Inc.",
             "Website"      : "http://www.abc.com"
           },
          @{ "ID"           : 2,
             "Company name" : "XYZ Inc.",
             "Website"      : "http://www.xyz.com"
           },
          @{ "ID"           : 3,
             "Company name" : "123 Inc.",
             "Website"      : "http://www.123.net"
           },
          // ... about 90 companies
          ],
    "Employees": @[
          @{ "ID"           : 1,
             "First name"   : "John",
             "Last name"    : "Doe"
           },
          @{ "ID"           : 2,
             "First name"   : "David",
             "Last name"    : "Green"
           },
          // ... about 500 employees
    ]
}

Now I'm facing the problem of relationships (which employees work in which company). I thought of adding and NSArray to the company NSDictionary which holds the IDs of the employees of that company. But somehow I'm afraid of bad performance as I would need to enumerate all companies each time I want to get the company which an employee works for.

Is there any better solutions for saving this kind of data? I think using SQLite or Core Data would be way to over-engineered and would cost too much development time...

EDIT: Please don't suggest Core Data in your comments and answers. Core Data is not an option as the data is very static with only few changes, and sorting is not needed. Also iCloud synchronization might be an option. Core Data has plenty of bugs when using iCloud...

Cezar
  • 55,636
  • 19
  • 86
  • 87
FrankZp
  • 2,022
  • 3
  • 28
  • 41
  • imho use sqlite even if you never used it before, it's still easier then trying to implement your own 'performant' relationship-model based on arrays and dictionaries. – peko Jul 26 '13 at 14:34
  • You can also use plists stored in your app bundle or sandbox. You can find here, http://developer.apple.com/library/ios/#documentation/general/Reference/InfoPlistKeyReference/Articles/AboutInformationPropertyListFiles.html. – Engnyl Jul 26 '13 at 14:44
  • 1
    By the time you have finished writing your own persistence model (bug free), you could have learn to manage CoreData properly, put in your CV and prepared your project to evolve and scale. 200 to 500 entity are a strong reason to use CoreData. Not too mention all that is related (fetched results controller, notifications ecc...). – Leonardo Jul 26 '13 at 14:45

2 Answers2

3

Core Data is cool, don't be afraid of it :) And I suggest you to use Core Data.

But if you don't want to learn modern technology which is popularized by Apple, you should to save your data in plist-files. There are many tutorials, here is nice sample.

Community
  • 1
  • 1
Valentin Shamardin
  • 3,569
  • 4
  • 34
  • 51
  • Yes, Core Data is cool and will be useful in this situation. I also recommend https://github.com/magicalpanda/MagicalRecord for ease of use. – Evgeny Aleksandrov Jul 26 '13 at 14:42
  • I used Core Data a lot. But as I said, this will be over-engineered (especially as I don't need sorting stuff etc. and as the DB is very static). Core Data comes also along with lot's of problems (full of bugs when using iCloud, migration problematics on app updates etc). Implementing the data model classes, the fetched results controller etc will take time with only very low benefit... – FrankZp Jul 26 '13 at 14:44
  • Look at MagicalRecord. It served me well even in small applications. And it doesn't add any clutter in code. – Evgeny Aleksandrov Jul 26 '13 at 14:47
  • @EvgenyAleksandrov This is also Core Data and as I said: I don't want to implement Core Data because the Db is very static, needs no sorting and Core Data is very buggy when using iCloud... – FrankZp Jul 26 '13 at 14:50
2

If your database is too small for Core Data, maybe NSCoding will work for you. I don't recommend storing your data in dictionaries and arrays (at runtime). Instead (since your data model is not too complex) implement model objects such as Employee and Company. These model objects should then implement the NSCoding protocol. It could look something like this:

@interface Employee : NSObject <NSCoding>
@property (nonatomic) NSString *firstName;
@property (nonatomic) NSString *lastName;
@property (nonatomic, weak) Company *company;
@end

@implementation Employee
- (id)initWithCoder:(NSCoder *)coder {
    self = [super init];
    if (self) {
        self.firstName = [coder decodeObjectForKey:@"FirstName"];
        self.lastName = [coder decodeObjectForKey:@"LastName"];
        self.company = [coder decodeObjectForKey:@"Company"];
    }
}
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.firstName forKey:@"FirstName"];
    [coder encodeObject:self.lastName forKey:@"LastName"];
    [coder encodeConditionalObject:self.company forKey:@"Company"];
}
@end

@interface Company : NSObject <NSCoding>
@property (nonatomic) NSString *name;
@property (nonatomic) NSString *website;
@property (nonatomic) NSArray *employees;
@end

@implementation Company
- (id)initWithCoder:(NSCoder *)coder {
    self = [super init];
    if (self) {
        self.name = [coder decodeObjectForKey:@"Name"];
        self.website = [coder decodeObjectForKey:@"Website"];
        self.employees = [coder decodeObjectForKey:@"Employees"];
    }
}
- (void)encodeWithCoder:(NSCoder *)coder {
    [coder encodeObject:self.name forKey:@"Name"];
    [coder encodeObject:self.website forKey:@"Website"];
    [coder encodeObject:self.employees forKey:@"Employees"];
}
@end

Now you can simply store everything with an NSKeyedArchiver:

[NSKeyedArchiver archiveRootObject:companiesArray toFile:somePath];

And load them with an NSKeyedUnarchiver:

NSArray *companiesArray = [NSKeyedUnarchiver unarchiveObjectWithFile:somePath];
DrummerB
  • 39,814
  • 12
  • 105
  • 142
  • I think 200-500 objects is not too small for Core Data, but it is too much for archiving. Core Data is faster in this case. – Valentin Shamardin Jul 26 '13 at 14:46
  • I would also use Core Data, but OP asked about an alternative and not performance. – DrummerB Jul 26 '13 at 14:47
  • @ValentinShamardin: Can you please clarify why 200-500 objects are too much for archiving? – FrankZp Jul 26 '13 at 14:48
  • Depends on how big your model is. How much data you save with each of the objects. But a couple hundred objects will most probably work fine. It's just that Core Data will perform better, because it can fetch just the data you actually need. With archiving you have to load and save the whole database at once. – DrummerB Jul 26 '13 at 14:57
  • @FrankZp, because saving with archiving need to save all your data. Core Data make it faster, because it saves only changes. – Valentin Shamardin Jul 26 '13 at 15:00
  • @DrummerB: On app launch the whole database is loaded from a plist to an `NSDictionary`. 85% of the apps functionality is about reading this data. There might be some modifications which are handled by copying the `NSDictionary` to mutable, replacing the changed object for the relevant key and saved then back to the plist. Can this become a performance issue? I mean this is only very small data and saving is not running in the main thread isn't it? – FrankZp Jul 26 '13 at 15:02