Reputation: 23
For a task tracking app, I'm using an array of NSDictionaries that contain certain details about the task—-duration, etc.
NSString *savedTaskName = addedTask.taskName;
NSString *savedTaskAccountName = addedTask.accountName;
NSString *savedTaskBillCode = addedTask.billCode;
NSString *savedTaskActivityCode = addedTask.activityCode;
NSNumber *savedTaskDuration = [NSNumber numberWithFloat:addedTask.taskDuration];
NSString *savedTaskTimeCode = addedTask.formattedTimeString;
NSDictionary *addedTaskData = [[NSDictionary alloc] initWithObjectsAndKeys:savedTaskName, kTaskName,
savedTaskAccountName, kAccountName,
savedTaskBillCode, kBillCode,
savedTaskActivityCode, kActivityCode,
savedTaskDuration, kTaskDuration,
savedTaskTimeCode, kTimeCode, nil];
Perhaps I'm making a newb mistake, but when I go to add addedTaskData to an NSMutableArray, the array only catches the first three values and keys of the dictionary.
Have I lost my mind? Why isn't it catching all? Curiously, asking for the count of dictionary keys returns the full amount.
Upvotes: 1
Views: 140
Reputation: 44876
initWithObjectsAndKeys
stops when it hits a nil value. If you're getting three keys/values, then:
NSDictionary *addedTaskData = [[NSDictionary alloc] initWithObjectsAndKeys:savedTaskName, kTaskName,
savedTaskAccountName, kAccountName,
savedTaskBillCode, kBillCode,
savedTaskActivityCode, kActivityCode, // <-- THIS IS NIL
savedTaskDuration, kTaskDuration,
savedTaskTimeCode, kTimeCode, nil];
You can use something like this instead:
NSDictionary *addedTaskData = [[NSDictionary alloc] initWithObjectsAndKeys:savedTaskName, kTaskName,
savedTaskAccountName, kAccountName,
savedTaskBillCode, kBillCode,
(savedTaskActivityCode ?: [NSNull null]), kActivityCode, // Or @""
savedTaskDuration, kTaskDuration,
savedTaskTimeCode, kTimeCode, nil];
Anything that could be nil should be protected like this.
If you're doing a bunch of them in a row, you can declare a local null variable:
id null = [NSNull null];
NSDictionary *addedTaskData = [[NSDictionary alloc] initWithObjectsAndKeys:(savedTaskName ?: null), kTaskName,
(savedTaskAccountName ?: null), kAccountName,
(savedTaskBillCode ?: null), kBillCode,
(savedTaskActivityCode ?: null), kActivityCode, // Or @""
(savedTaskDuration ?: null), kTaskDuration,
(savedTaskTimeCode ?: null), kTimeCode, nil];
Upvotes: 3
Reputation: 1045
Try to use literals like this:
NSString *savedTaskName = addedTask.taskName;
NSString *savedTaskAccountName = addedTask.accountName;
NSString *savedTaskBillCode = addedTask.billCode;
NSString *savedTaskActivityCode = addedTask.activityCode;
NSNumber *savedTaskDuration = [NSNumber numberWithFloat:addedTask.taskDuration];
NSString *savedTaskTimeCode = addedTask.formattedTimeString;
// Use literals and see your code doesn't crash
NSDictionary *addedTaskData = @{kTaskName: savedTaskName,
kAccountName: savedTaskAccountName,
savedTaskBillCode: savedTaskBillCode,
savedTaskActivityCode: savedTaskActivityCode
savedTaskDuration: savedTaskDuration
savedTaskTimeCode: savedTaskTimeCode};
And see your code doesn't crash
Upvotes: 0
Reputation: 949
When not using the literal syntax there is a chance that you will run into nil termination issues. If savedTaskDuration
is actually nil
then it's going to chop off the rest of the NSDictionary.
Take a look with the debugger and see if you have a nil value in there somewhere. Then run the Modern Objective-C refactor tool and convert that sucker to a NSDictionary literal so that you are protected from this in the future.
For reference the Literal syntax is like this:
NSDictionary *addedTaskData = @{@"Key" : @"Value", @"AnotherKey" : @"AnotherValue"};
Upvotes: 0