Perché è solo attributo della mia oggetto che viene correttamente scritto in un file?
-
10-10-2019 - |
Domanda
Così sto cercando di scrivere un NSMutableArray di oggetti personalizzati (un "Corso" che rappresenta un corso universitario per un'applicazione Planner Corso) in un file quando i miei termina applicazione e poi leggere quella matrice dal file nel ViewController rilevante che si avvarrà dei dati quando l'applicazione si avvia.
Ecco il codice in questione:
CoursesAppDelegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
coursesViewController = [[SampleHomeScreen alloc] initWithNibName:@"SampleHomeScreen" bundle:nil];
NSString *filePath = [self dataFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
[coursesViewController setCourses:[NSKeyedUnarchiver unarchiveObjectWithFile: filePath]];
}
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(applicationWillTerminate:)name:UIApplicationWillTerminateNotification object:app];
[window addSubview:coursesViewController.view];
[window makeKeyAndVisible];
return YES;
}
- (NSString *)dataFilePath {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *path = [documentsDirectory stringByAppendingPathComponent:@"data.plist"];
NSLog(@"%@", path);
return path;
}
/**
applicationWillTerminate: saves changes in the application's managed object context before the application terminates.
*/
- (void)applicationWillTerminate:(UIApplication *)application {
NSLog(@"%@", [coursesViewController courses]);
[NSKeyedArchiver archiveRootObject:[coursesViewController courses] toFile:[self dataFilePath]];
}
Course.h:
@interface Course : NSObject <NSCoding> {
NSString *name; //e.g. ECS 189H
double grade, totalWeight; //course grade in %
NSMutableArray *list;
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic) double grade, totalWeight;
@property (nonatomic, retain) NSMutableArray *list;
-(Course *)initWithName:(NSString *)courseName;
@end
Course.m:
@implementation Course
@synthesize name, grade, totalWeight, list;
-(Course *)initWithName:(NSString *)courseName {
name = [courseName retain];
grade = -1.0;
totalWeight = 0.0;
list = [[NSMutableArray alloc] init];
[super init];
return self;
}
-(Course *)initWithCoder:(NSCoder *)aDecoder {
self.name = [aDecoder decodeObjectForKey:@"name"];
self.grade = [aDecoder decodeDoubleForKey:@"grade"];
self.totalWeight = [aDecoder decodeDoubleForKey:@"totalWeight"];
self.list = [aDecoder decodeObjectForKey:@"list"];
[super init];
return self;
}
- (void) encodeWithCoder: (NSCoder *)coder
{
[coder encodeObject:name forKey:@"name"];
[coder encodeDouble:grade forKey:@"grade"];
[coder encodeDouble:totalWeight forKey:@"totalWeight"];
[coder encodeObject:list forKey:@"list"];
}
-(void)dealloc {
[name release];
[list release];
[super dealloc];
}
@end
[corsi coursesViewController] è il NSMutableArray che contiene gli oggetti del corso. So per certo che esso contiene i dati validi.
Quindi i problemi sono, 1: L'applicazione salva data.plist SOLO quando l'eseguo da Xcode (cioè scegliere "Compila e fuggi" in Xcode). 2: carica i dati dal plist, ma tutto ciò che viene salvato sono (rispettivamente -1 e 0) i nomi dei corsi e i valori predefiniti per grado e pesoTotale. Quindi, in realtà essi vengono salvati come se initWithName stato chiamato su di loro prima.
Questa è la mia prima vera immergersi in un applicazione piuttosto avanzata iOS, così come io sono un novizio di questo, forse ho lasciato fuori alcune importanti informazioni. Se questo è il caso, per favore fatemelo sapere e vi aggiornerò la questione.
Grazie! -HT
P.S. Se è rilevante, ho doNotRunInBackground nel set Info.plist su true.
Soluzione
Il vostro stanno cercando di valori impostati in oggetto prima che sia stato inizializzato. E inizializzazione quindi ripristinare i valori.
-(Course *)initWithName:(NSString *)courseName {
name = [courseName retain]; // <- Accessing ivar before self is initialized
grade = -1.0; // <- Accessing ivar before self is initialized
totalWeight = 0.0; // <- Accessing ivar before self is initialized
list = [[NSMutableArray alloc] init]; // <- Accessing ivar before self is initialized
[super init]; // initialization resets your values !!!!
return self;
}
Inoltre si sta ignorando il valore di ritorno di init di eccellente, che funziona bene il 98% di tutti i casi, ma vi consiglio di sempre utilizzare uno schema di inizializzazione corretta:
- (id)init {
if (self = [super init]) {
// It's save to access ivars here
}
return self
}
In Cocoa un metodo init può restituire un oggetto diverso, poi quello che è stato assegnato. Così si deve di sé assegnare alla init del super-.
Così, il vostro init dovrebbe essere simile:
-(Course *)initWithName:(NSString *)courseName {
if (self = [super init]) {
name = [courseName retain];
grade = -1.0;
totalWeight = 0.0;
list = [[NSMutableArray alloc] init];
}
return self;
}
Lo stesso vale per initWithCoder:(NSCoder *)coder
.