Reputation: 4413
I need to store multi-level data for a flash card app I'm writing and I could use some help figuring out 1) How to manage the data and 2) How to store it.
The data is broken down like this: a) Card contains 2 strings b) Pack contains a String "PackName" and an array of Cards c) Deck contains a String "DeckName" and an array of Packs
Right now I have 3 Classes: Card, Pack, Deck.
//Card.h
@interface Card : NSObject {
NSString *primaryPhrase;
NSString *secondaryPhrase;
}
@property (nonatomic,retain)NSString *primaryPhrase;
@property (nonatomic,retain)NSString *secondaryPhrase;
@end
Card.m
@implementation Card
@synthesize primaryPhrase;
@synthesize secondaryPhrase;
-(id)init{
if(self=[super init]){
}
return self;
}
@end
Pack.h
@interface Pack : NSObject{
NSString *packName;
NSMutableArray *cards; //array of card classes
BOOL isInUse;
}
@property (nonatomic,retain)NSMutableArray *cards;
@property (nonatomic,retain)NSString *packName;
@property (nonatomic,assign)BOOL isInUse;
@end
Pack.m
@implementation Pack
@synthesize packName;
@synthesize cards;
@synthesize isInUse;
-(id)init{
if(self=[super init]){
self.isInUse=YES;
}
return self;
}
@end
Deck.h
@interface Deck : NSObject <NSCoding>{
NSString *deckName;
NSMutableArray *packs; //array of pack classes
NSString *primaryLang;
NSString *secondaryLang;
}
@property (nonatomic,retain)NSMutableArray *packs;
@property (nonatomic,retain)NSString *deckName;
@property (nonatomic,retain)NSString *primaryLang;
@property (nonatomic,retain)NSString *secondaryLang;
- (void) encodeWithCoder:(NSCoder*)encoder;
- (id) initWithCoder:(NSCoder*)decoder;
@end
Deck.m
#import "Deck.h"
@implementation Deck
@synthesize packs;
@synthesize deckName;
@synthesize primaryLang;
@synthesize secondaryLang;
//Default settings for each new Deck
-(id)init{
if(self=[super init]){
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder{
[encoder encodeObject:packs forKey:@"packs"];
[encoder encodeObject:deckName forKey:@"deckName"];
[encoder encodeObject:primaryLang forKey:@"primaryLang"];
[encoder encodeObject:secondaryLang forKey:@"secondaryLang"];
}
-(id)initWithCoder:(NSCoder*)decoder{
if(self=[super init]){
packs=[decoder decodeObjectForKey:@"packs"];
deckName=[decoder decodeObjectForKey:@"deckName"];
primaryLang=[decoder decodeObjectForKey:@"primaryLang"];
secondaryLang=[decoder decodeObjectForKey:@"secondaryLang"];
}
return self;
}
@end
Then I use an NSMutableArray "allDecks" to hold Decks, which in turn contain Cards, but I haven't even been able to get this to work (no errors, but "pack name" is always null):
for(int i=0; i<=2; i++){
Deck *newdeck=[[Deck alloc]init];
[globDat.allDecks addObject:newdeck];
}
((Deck *)[globDat.allDecks objectAtIndex:0]).deckName=@"DeckName 0";
((Deck *)[globDat.allDecks objectAtIndex:1]).deckName=@"DeckName 1";
((Deck *)[globDat.allDecks objectAtIndex:2]).deckName=@"DeckName 2";
for(int i=0; i<=2; i++){
Pack *newpack=[[Pack alloc] init];
[((Deck *)[globDat.allDecks objectAtIndex:i]).packs addObject:newpack];
}
for(int j=0; j<+2; j++){
((Pack *)[((Deck *)[globDat.allDecks objectAtIndex:0]).packs objectAtIndex:j]).packName=@"pack name";
}
NSLog(@"*** NIL sample pack name=%@",((Pack *)[((Deck *)[globDat.allDecks objectAtIndex:0]).packs objectAtIndex:0]).packName);
//always returns null
It's pretty cumbersome to work the structure. Is this the best way to manage this data?
Plus, the encoding doesn't seem to save the embedded arrays (Pack and Card).
Upvotes: 0
Views: 144
Reputation: 12979
Honestly I would continue with the way you are doing things. The reason that Pack
and Card
aren't being saved is because they each need to implement the encodeWithCoder:
and initWithCoder:
methods.
Card.h
@interface Card : NSObject
@property (nonatomic,retain)NSString *primaryPhrase;
@property (nonatomic,retain)NSString *secondaryPhrase;
@end
Card.m
@implementation Card
@synthesize primaryPhrase, secondaryPhrase;
-(id)init{
if(self=[super init]){
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder{
[encoder encodeObject:primaryPhrase forKey:@"primaryPhrase"];
[encoder encodeObject:secondaryPhrase forKey:@"secondaryPhrase"];
}
-(id)initWithCoder:(NSCoder*)decoder{
if(self=[super init]){
primaryPhrase=[decoder decodeObjectForKey:@"primaryPhrase"];
secondaryPhrase=[decoder decodeObjectForKey:@"secondaryPhrase"];
}
return self;
}
@end
Pack.h
@interface Pack : NSObject
@property (nonatomic,retain)NSMutableArray *cards;
@property (nonatomic,retain)NSString *packName;
@property (nonatomic,assign)BOOL isInUse;
@end
Pack.m
@implementation Pack
@synthesize packName, cards, isInUse;
-(id)init{
if(self=[super init]){
self.isInUse=YES;
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder{
[encoder encodeObject:packName forKey:@"packName"];
[encoder encodeObject:cards forKey:@"cards"];
[encoder encodeObject:[NSNumber numberWithBool:isInUse] forKey:@"isInuse"];
}
-(id)initWithCoder:(NSCoder*)decoder{
if(self=[super init]){
packName=[decoder decodeObjectForKey:@"packName"];
cards=[decoder decodeObjectForKey:@"cards"];
isInUse=[[decoder decodeObjectForKey:@"isInUse"] boolValue];
}
return self;
}
@end
Deck.h
@interface Deck : NSObject <NSCoding>
@property (nonatomic,retain)NSMutableArray *packs;
@property (nonatomic,retain)NSString *deckName;
@property (nonatomic,retain)NSString *primaryLang;
@property (nonatomic,retain)NSString *secondaryLang;
@end
Deck.m
#import "Deck.h"
@implementation Deck
@synthesize packs, deckName, primaryLang, secondaryLang;
-(id)init{
if(self=[super init]){
}
return self;
}
-(void)encodeWithCoder:(NSCoder*)encoder{
[encoder encodeObject:packs forKey:@"packs"];
[encoder encodeObject:deckName forKey:@"deckName"];
[encoder encodeObject:primaryLang forKey:@"primaryLang"];
[encoder encodeObject:secondaryLang forKey:@"secondaryLang"];
}
-(id)initWithCoder:(NSCoder*)decoder{
if(self=[super init]){
packs=[decoder decodeObjectForKey:@"packs"];
deckName=[decoder decodeObjectForKey:@"deckName"];
primaryLang=[decoder decodeObjectForKey:@"primaryLang"];
secondaryLang=[decoder decodeObjectForKey:@"secondaryLang"];
}
return self;
}
Upvotes: 1
Reputation: 9185
I'll post this as an answer, though it's really an opinion.
I would use Core Data for the model layer. You will not need to deal with serializing your object graph as your are now. Rather, the object graph persistence is largely handled by the framework. There is a learning curve - per Apple, it is not an "entry-level technology" - but it will be much more manageable in the long run.
As for the issue with serialization of the arrays in your object graph, NSMutableArray
conforms to the NSCoding
protocol; there is some other issue. Instead of:
packs=[decoder decodeObjectForKey:@"packs"];
don't you mean:
self.packs = [decoder decodeObjectForKey:@"packs"];
or
packs = [[decoder decodeObjectForKey:@"packs"] retain];
(I'm assuming you're not using ARC...)
Upvotes: 1