【发布时间】:2014-05-26 15:13:09
【问题描述】:
我是 Xcode 的新手,请帮忙。
我有三个视图控制器(子类UIViewController)和一个模型类(子类NSObject)。
当应用启动时 -->"ViewController.h" 加载然后导航到
--> "DetailsViewController.h" --> "AddHoursViewController.h"
使用 navigationButtons 调用相关的 prepareForSegue 和 UnwindToSeque 方法,我是最新的 xcode 版本并使用“ARC”。
我的问题是应用启动正常。它加载“monthArray”,而不是“grossMutableArray”(希望它会加载 0000.00 个对象)。一旦我导航到“AddHoursViewController.h”(堆栈中的第三个)并尝试返回(unwindToSegue 调用它调用[dataModel saveDataToDisk]; 应用程序崩溃。如果我将[dataModel saveDataToDisk]; 方法注释掉,应用程序导航正常而不加载任何数据。
有趣的是在“重置 iOS 模拟器并删除所有模拟器数据”之后,如果我在启动前在 -(void)loadDataFromDisk 中注释掉 self.grossPayArray = [rootObject objectForKey:kGrossPayArrayKey];,应用程序启动比 --> 停止模拟器 --> 删除评论 --> 再次重新启动并一切正常。
在使用 Google 之后,我尝试了各种方法,但似乎没有什么对我有用。我认为init 方法需要修改,但我无法理解它,请帮助。
相关代码和崩溃日志:
#import "DataModel.h"
#import "ViewController.h"
#import "DetailsViewController.h"
#import "AddHoursViewController.h"
NSString *const kMonthArrayKey = @"MonthArray";
NSString *const kGrossPayArrayKey = @"GrossPayArray";
NSUInteger indexNumber;
ViewController *viewController;
@implementation DataModel
- (id)init
{
self = [super init];
if (self) {
self.monthArray = [NSArray arrayWithObjects:@"Apr", @"May", @"Jun", @"Jul", @"Aug", @"Sep", @"Oct", @"Nov", @"Dec", @"Jan", @"Feb", @"Mar", nil];
self.grossPayArray = [NSMutableArray arrayWithObjects:@"0000.00", @"0000.00", @"0000.00", @"0000.00", @"0000.00", @"0000.00", @"0000.00", @"0000.00", @"0000.00", @"0000.00", @"0000.00", @"0000.00", nil];
[self loadDataFromDisk];
//NSLog(@"init method called");
}
return self;
}
//NSCODING
-(void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:self.monthArray forKey:kMonthArrayKey];
[encoder encodeObject:self.grossPayArray forKey:kGrossPayArrayKey];
NSLog(@"-(void)encodeWithCoder:(NSCoder *)encoder method called");
}
//decoding data from file
-(id)initWithCoder:(NSCoder *)decoder
{
self = [super init];
if (!self){
return nil;
}
self.grossPayArray = [decoder decodeObjectForKey:kGrossPayArrayKey];
return self;
}
#pragma mark Methods associated with saving data on the disk for this class
//file path where data resides
-(NSString*)pathForDataFile
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *pathToDirectory = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *fileFolder = [pathToDirectory objectAtIndex:0];
NSString *fileName = @"MyAppfileName";
if ( [fileManager fileExistsAtPath:fileFolder] == NO)
{
// NSLog(@"pathForDataFile does not exist %@", filePath);
[fileManager createDirectoryAtPath:fileFolder withIntermediateDirectories:NO attributes:nil error:nil];
NSLog(@"%@ documentDirectory", fileName);
}
return [fileFolder stringByAppendingPathComponent:fileName];
}
//Method to save data
-(void)saveDataToDisk
{
NSString *path = [self pathForDataFile];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSUInteger indexNumber = [defaults integerForKey:@"Index number"];
self.rootObject = [NSMutableDictionary dictionary];//dictionary creation
[self.grossPayArray replaceObjectAtIndex:indexNumber withObject:basicPayString];
[self.rootObject setObject:[self grossPayArray] forKey:kGrossPayArrayKey];
[NSKeyedArchiver archiveRootObject:self.rootObject toFile:path];}
//method to load data
- (void)loadDataFromDisk
//comment out eg grossArray array, loads it from -init, after first launch and invoking (self saveDataToDisk] --> stop app --> remove double slashed --> relaunch, will than replace object at index
//putting arrays under this code replaces object at index for chosen month and keeps one added before. if remove array from here replaces object at index but puts values from init methods in other objects.
{
NSString *path = [self pathForDataFile];
//NSLog(@"path in loadDataFromDisk %@", path);
NSDictionary *rootObject;
rootObject = [NSKeyedUnarchiver unarchiveObjectWithFile:path];
self.grossPayArray = [rootObject objectForKey:kGrossPayArrayKey];
}
-(id)initWithDocPath:(NSString *)docPath
{
if ((self = [super init])) {
_docPath = [docPath copy];
}
_docPath = [self pathForDataFile];
//NSLog(@"doc path init %@", _docPath);
return self;
}
@end
//////////////////////////////////////////////////////////////////////////////////////////////////////////错误日志/崩溃日志当展开到segue调用时调用[dataModel saveDataToDisk];如果对 saveDataToDisk 的调用被注释掉,那么应用程序可以在不加载任何数据的情况下正常导航。/////////
2014-05-26 15:25:27.596 CollectionFromNSObject[1179:60b] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** setObjectForKey: object cannot be nil (key: grossPayArray)'
*** First throw call stack:
(
0 CoreFoundation 0x018de1e4 __exceptionPreprocess + 180
1 libobjc.A.dylib 0x0165d8e5 objc_exception_throw + 44
2 CoreFoundation 0x01967eb8 -[__NSDictionaryM setObject:forKey:] + 888
3 CollectionFromNSObject 0x0000868f -[DataModel saveDataToDisk] + 2927
4 CollectionFromNSObject 0x00063b13 -[DetailsViewController unwindToDetailsViewController:] + 19203
5 libobjc.A.dylib 0x0166f82b -[NSObject performSelector:withObject:] + 70
6 UIKit 0x009f6a91 -[UIStoryboardUnwindSegueTemplate _perform:] + 536
7 UIKit 0x00881f87 -[UIStoryboardSegueTemplate perform:] + 115
8 libobjc.A.dylib 0x0166f880 -[NSObject performSelector:withObject:withObject:] + 77
9 UIKit 0x0031f3b9 -[UIApplication sendAction:to:from:forEvent:] + 108
10 UIKit 0x0060c8df -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 139
Continues...................
【问题讨论】:
-
嗯,它的说法是
setObjectForKey: object cannot be nil,所以检查参数,看看它是否曾经nil,然后从那里调试。在提供代码和崩溃日志方面做得很好! -
这里的原因不能比 Xcode 已经在做的更好地解释了:“setObjectForKey: object cannot be nil (key: basicPayArray)”
-
键:basicPayArray 是另一个数组。我删除了,因为它相同。因此,您可以安全地将其读取为 Key:grossPayArray。是的,但是当我在第一次启动时注释掉数组以启动后续启动时会发生什么。
-
我正在寻找我的代码中的建议。因为我无法在第一次启动应用程序时从 -(id)init 启动数组,而不是在启动应用程序和用户生成数据时开始替换/保存同一 NSMutableArray(grossArray) 中的数据。
-
为了将来参考编辑您之前的问题会比发布新问题更好。它仍然会将它撞到首页。
标签: ios objective-c nsmutablearray init