所以当我的应用程序终止时,我正在尝试将一个自定义对象的NSMutableArray(一个代表Course Planner应用程序的大学课程的“课程”)写入文件,然后将该数组从文件中读取到相关的ViewController中将在应用程序启动时使用数据。
以下是相关代码:
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
[coursesViewController courses]是保存课程对象的NSMutableArray。我知道它拥有有效的数据。
问题是, 1:仅当我从xcode运行它时,应用程序才会保存到data.plist(即在xcode中单击“编译并运行”)。 2:它从plist加载数据,但所有保存的是课程名称和grade和totalWeight的默认值(分别为-1和0)。所以他们真的得到了保存,好像首先在他们身上调用了initWithName。
这是我第一次真正深入研究一个相当高级的iOS应用程序,因此我是一个新手,我可能遗漏了一些重要的信息。如果是这种情况,请告诉我,我会更新问题。
谢谢! -HT
P.S。如果它是相关的,我将info.plist中的doNotRunInBackground设置为true。
答案 0 :(得分: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方法可以返回一个不同的对象,然后是已分配的对象。所以你必须将自己分配给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
。