I will begin by saying that I figured this out at about 9:30 last night.

On Dec 1, 2008, at 7:08 PM, [EMAIL PROTECTED] wrote:

// Notifies of change of data in table view. Make sure to reflect changes in datasource. - (void)tableView:(NSTableView *)aTableView setObjectValue: (id)anObject forTableColumn:(NSTableColumn *)aTableColumn row: (NSInteger)rowIndex
{
        NSString *columnID = [aTableColumn identifier];
NSMutableArray *scheduleArray = [NSMutableArray arrayWithArray:_schedules];
        
// If deactivate time was edited, we create a new schedule with just that changed.
        if ([columnID isEqualToString:kScheduleDeactivateString]) {
                NSLog(@"Deactivate anObject = %@", anObject);
[[scheduleArray objectAtIndex:rowIndex] setDeactivate:(NSNumber *) [anObject intValue]];

What are you doing here? You have an object (anObject). Presumably you think it's an NSNumber. Then, you ask for its intValue, which returns... an int. An int is _not_ an object, of course. You then cast that int to an NSNumber*, which is almost certainly wrong. You then pass it to some method which is probably expecting a pointer to an actual object, not an int posing as a pointer.

The reason for the undefined object here (anObject) is that this method is actually a delegate method of NSTableView. I was under the impression that the delegate methods must be used as is (the prototype anyway) because that's the message NSTableView is going to send to the delegate. Depending on what table column was edited (as per the aTableColumn parameter) I need the object (presumably an NSString* since all of the table fields are text fields) to be either an NSString* or an NSNumber*. I know intValue returns an int, and I'm perfectly aware that an int is not an object, that's obvious. I did think there was some bridging in place, however, for NSNumber, but you are right, there isn't. What I really needed was:

[NSNumber numberWithInt:[anObject intValue]]

After changing that part of the line, this part of the method worked without incident.


        }
// If activate time was edited, we create a new schedule with just that changed.
        else if ([columnID isEqualToString:kScheduleActivateString]) {
                NSLog(@"Activate anObject = %@", anObject);
[[scheduleArray objectAtIndex:rowIndex] setActivate:(NSNumber *) [anObject intValue]];

You do the same here.


        }
// If name was edited, we create a new schedule with just that changed.
        else if ([columnID isEqualToString:kScheduleNameString]) {
                NSLog(@"Title anObject = %@", anObject);
[[scheduleArray objectAtIndex:rowIndex] setTitle:(NSString *)anObject];
        }
        
// Iterate through the array to create a new one of NSDictionaries, not schedules.
        NSMutableArray *tmpArray;

You have declared a pointer, but you haven't set it to point to anything, let alone anything meaningful. It just contains garbage at this point.

        for (Schedule *schedules in scheduleArray) {
                [tmpArray addObject:[schedules toDictionary]];

You're calling methods on an uninitialized pointer. This will probably crash. If you're unlucky, the bug will be hidden by happenstance (tmpArray may happen to be nil because that's what was left on the stack).

You needed to initialize tmpArray to point to an actual NSMutableArray:

        NSMutableArray* tmpArray = [NSMutableArray array];


                NSLog(@"Adding this to array %@", [schedules toDictionary]);
        }
        
        // Write the array to preferences in /Library/Preferences.
CFPreferencesSetValue(ScheduleKey, (CFArrayRef)tmpArray, ApplicationID, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);

Again, tmpArray doesn't contain anything meaningful. So, attempting to write it out will have undefined results -- probably the crash you're seeing.

CFPreferencesSynchronize(ApplicationID, kCFPreferencesAnyUser, kCFPreferencesCurrentHost);
        
}

The pref pane runs fine. I can add items which calls my addSchedule method and just adds a blank item to the array. When I edit the title, it appears to work fine from the gui, but nothing is written to the plist. If I edit the activate or deactivate fields then I get the following error and System Preferences crashes.

12/1/08 6:39:59 PM System Preferences[2301] Adding this to array {
  activate = 100;
  deactivate = 1130;
  name = "New Schedule";
}
12/1/08 6:39:59 PM System Preferences[2301] *** -[NSCFString stringValue]: unrecognized selector sent to instance 0x16e63740

Does anyone have any insight about writing array's of dicts to preferences?

You were also right about the array, I forgot those two little keywords, a simple oversight. Instead of going through the mess of making an NSMutableArray and casting as a CFArrayRef, I decided to just make a CFArrayRef from the get go and ended up using CoreFoundation since that's what CFPreferences expects.

Your problem isn't in writing stuff to preferences. Your problem is that you're not constructing valid objects. I think you need to review the basics of C, Objective-C, and Cocoa. This is pretty fundamental stuff.

Regards,
Ken


Thanks for the ideas,
Ryan

_______________________________________________

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to