¿Por qué es sólo un atributo de mi objeto que se está escrito correctamente en un archivo?

StackOverflow https://stackoverflow.com/questions/4385721

  •  10-10-2019
  •  | 
  •  

Pregunta

Así que estoy tratando de escribir un NSMutableArray de objetos personalizados (un "curso" que representa un curso de la universidad para una aplicación Planificador de golf) en un archivo cuando ya mis terminada su aplicación leen entonces esa matriz a partir del archivo en el que ViewController relevante hará uso de los datos cuando se inicia la aplicación.

Este es el código correspondiente:

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

[cursos coursesViewController] es el NSMutableArray que contiene los objetos del curso. Sé que es un hecho de que contiene datos válidos.

Así son los problemas, 1: La aplicación guarda a data.plist SOLAMENTE cuando lo ejecuto desde Xcode (es decir, haga clic en "compilar y ejecutar" en Xcode). 2: carga de datos desde el plist, pero todo lo que es salvado son los nombres de los cursos y los valores por defecto de grado y pesoTotal (-1 y 0, respectivamente). Así que en realidad se guardan como si initWithName fue llamado en ellos en primer lugar.

Esta es mi primera ahondar real en una aplicación bastante avanzada IOS, así como yo soy un novato en esto, que puede haber dejado fuera alguna información importante. Si ese es el caso, por favor hágamelo saber y voy a actualizar la cuestión.

Gracias! -HT

p.s. Si es relevante, no tengo doNotRunInBackground en el conjunto info.plist true.

¿Fue útil?

Solución

Su están tratando de valores establecidos en su objetivo antes de que se haya inicializado. Y la inicialización se restablecerá sus valores.

-(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;
}

Además se está haciendo caso omiso valor de retorno del súper init, que no tendrán ningún problema el 98% de todos los casos, pero recomiendo a siempre utilizar un esquema de inicialización adecuada:

- (id)init {
    if (self = [super init]) {
        // It's save to access ivars here
    }
    return self
}

En Cocoa un método init puede devolver un objeto diferente, entonces el uno que se asignó. Por lo que debe auto asignar a init del súper.

Por lo tanto, el init debe ser similar a:

-(Course *)initWithName:(NSString *)courseName {
    if (self = [super init]) {
        name = [courseName retain];
        grade = -1.0;
        totalWeight = 0.0;
        list = [[NSMutableArray alloc] init];
    }
    return self;
}

Lo mismo se aplica a initWithCoder:(NSCoder *)coder.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top