1

因此,当我的应用程序终止时,我尝试将自定义对象的 NSMutableArray(代表 Course Planner 应用程序的大学课程的“课程”)写入文件,然后将该数组从文件中读取到将使用的相关 ViewController应用程序启动时的数据。

以下是相关代码:

课程AppDelegate.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]];
}

课程.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

课程.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

[coursesViewController courses] 是保存课程对象的 NSMutableArray。我知道它拥有有效数据这一事实。

所以问题是,1:只有当我从 xcode 运行应用程序时,应用程序才会保存到 data.plist(即在 xcode 中单击“编译并运行”)。2:它从 plist 加载数据,但保存的只是课程名称以及成绩和总权重的默认值(分别为 -1 和 0)。所以实际上它们被保存,就好像 initWithName 被首先调用它们一样。

这是我第一次真正深入研究一个相当高级的 iOS 应用程序,所以作为一个新手,我可能遗漏了一些重要信息。如果是这种情况,请告诉我,我会更新问题。

谢谢!-H T

ps 如果相关,我将 info.plist 中的 doNotRunInBackground 设置为 true。

4

1 回答 1

1

您正在尝试在对象初始化之前设置它的值。然后初始化将重置您的值。

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

此外,您忽略了 super 的 init 返回值,这在所有情况下都可以正常工作 98%,但我建议始终使用正确的初始化方案:

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

在 Cocoa 中,一个 init 方法可能会返回一个不同的对象,然后是分配的那个。所以你必须将self分配给super的init。

因此,您的 init 应如下所示:

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

这同样适用于initWithCoder:(NSCoder *)coder

于 2010-12-08T10:12:43.613 回答