Problem with saving NSDate to the CoreData context
I'm trying to save managed object with one of the attribute's type Date to the managedObjectContext
.
Code is like:
reminder.eventDate = selectedDate;
NSLog(@"Date: %@", selectedDate);
NSError *error = nil;
if (![reminder.managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
during context saving program crashes with SIGABRT. Here is a console log:
2011-02-28 00:50:18.817 MyApp[9021:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSDate isEqualToString:]: unrecognized selector sent to instance 0x4e73490' *** Call stack at first throw: ( 0 CoreFoundation 0x01057be9 __exceptionPreprocess + 185 1 libobjc.A.dylib 开发者_StackOverflow 0x011ac5c2 objc_exception_throw + 47 2 CoreFoundation 0x010596fb -[NSObject(NSObject) doesNotRecognizeSelector:] + 187 3 CoreFoundation 0x00fc9366 ___forwarding___ + 966 4 CoreFoundation 0x00fc8f22 _CF_forwarding_prep_0 + 50
Does anyone knows why I have that?
Second question is why when I check in debugger mode selectedDate
isn't NSDate type but __NSDate (double underscore in front).
Thanks!
UPDATE:
I did some changes to easier catch the bug. so code now is like:
reminder.eventDate = [NSDate date];
NSLog(@"Date: %@", selectedDate);
NSError *error = nil;
if (![reminder.managedObjectContext save:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
so, here we save definitely NSDate. reminder.eventDate is NSDate too. But I still have this error. If I comment reminder.eventDate = [NSDate date];
saving throws another error (date is mandatory field in NSData, so save: returns error "The operation couldn’t be completed." with eventDate = nil;
.
CoreData structure is checked multiple times - eventDate has Date type.
UPDATE (Problem solved): Finally I found the problem. eventDate
was set as key for the detailTextLabel.text
in my tableview cells (I used KVO for that). So if was no direct call and I wasn't able to find any method invokation for the eventDate
. Strange thing is that crash was on the save
method, not later. And in the call stack there is no tableView:cellForRowAtIndexPath:
method at all...
Silly as it sounds, I would suggest that you double check that both your reminder object and associated managedObjectContext are valid.
You are certain that your model correctly models eventDate as a date attribute, and you are also certain that the object you pass to the eventDate attribute is a NSDate object. So, try verifying that reminder and its managedObjectContext are not nil.
Finally, verify if all of the other attributes and relations are correctly set (check if you actually insert all of the required attributes and relations, check if the objects you use are of the correct type etc).
This will also help narrowing the possibilities.
EDIT: You can verifying what is actually happening inside your sqlite database. Simply add the following as an argument before starting your application:
-com.apple.CoreData.SQLDebug 1
see the documentation.
How you do this depends on your installed toolset (Xcode 3 or 4). I am using the latest Xcode 4 and to add an argument you simply select your current scheme, then you select Run "your app name" and click the Arguments tab to add the argument.
That sounds like you have your data model set up to expect a string in the eventDate property, rather than a date.
NSDate is a "class cluster", which means that instances you actually deal with will be instances of some private subclass of NSDate (in this case, __NSDate).
As for the error, I agree with Simon Goldeen that the most likely reason is that the data model or the NSManagedObject subclass is expecting a string rather than a date.
Just to add to what has already been said:
It doesn't have to be a problem with the model or the NSManagedObject subclass. It could just be a piece of code almost anywhere that calls isEqualToString:
. Somewhere you've got an object that the code assumes should be a NSString but is instead a NSDate object. I would look at any code that might convert dates to strings.
However, since it happens upon save I would look at any customizations you might have done to the subclass.
The place to start is by searching the project for isEqualToString:
.
Update:
Since isEqualToString
is a testing method it can be activated anytime you do a compare for a string such as in a sort. I couldn't reproduce your exact error but the following code does something similar:
id idDate=[NSDate date];
NSString *bob=[NSString stringWithString:@"bob"];
NSString *steve=@"test this";
steve=idDate;
NSLog(@"test=%@",([steve compare:bob]) ?@"YES":@"NO");
... complies but throws an exception:
-[NSCFString timeIntervalSinceReferenceDate]: unrecognized selector sent to instance 0x4040
So, you can see how these types of errors can slip in. It's also a demonstration for why you should be careful with the use of id
.
I chased this one too. Since your model and class definitions are good, and assuming your value is good, then there's one less obvious place that fixed it for me ... Delete the app from the device and clean your build, and make sure any seeded sqlite files are new too. My device or build folder had an old store or model lingering that caused this. What other frameworks are you using? RestKit, JSON, etc? Anything that overloads a class method could also be a suspect. ... hard to tell whats getting compared in that save ... My guess is an old store
精彩评论