4

I've got some Core Data code that follows Apple's sample code precisely (the Fetching Attribute Values that Satisfy a Given Function example). I'm using it to get the max value of a field, so I can then increment it when I insert the next object of that entity type.

I couldn't get the code to work at all, until I switched my Store Type from NSXMLStoreType to NSSQLiteStoreType, then all of a sudden everything seemed to be working. However, that's not the case. I noticed that it would always return the same value, even when I inserted objects with a higher one. But, after I quit and reopened (and thus the data was persisted and read back in), it would update with the new inserts.

So then I started committing and saving after each insert. After the first "autosave" though, I get the error below (twice in a row):

-[NSCFNumber count]: unrecognized selector sent to instance 0x100506a20

This occurs (two times in a rows) when I execute the fetch request once:

NSArray *objects = [context executeFetchRequest:request error:&error];

Update

I ran my code through the Zombies instrument, and was able to take a look at the object which is getting the error. The call that runs malloc to allocate it is: -[NSUserDefaults(NSUserDefaults) initWithUser:]. Since I don't have any of my own defaults set, I don't know what object this could be.

Update 2

I searched through all of my code for "release" and commented out every release or autorelease that the static analyzer didn't complain about. I still got the errors. I even went so far as to comment out every last release/autorelease in my code, and still got it. Now I'm fairly certain my own code isn't over-releasing.

Update 3

This post seems to be having the same problem, but his solution doesn't make sense. He changed the result type from NSDictionaryResultType to NSManagedObjectResultType, which produces an incorrect result. Instead of getting back a single value (the max that I'm looking for, that returns back every object of my entity class in the managed object context.

Here are the top-most levels of the stack trace (when I have it break on the exception, the first time):

#0  0x7fff802e00da in objc_exception_throw
#1  0x7fff837d6110 in -[NSObject(NSObject) doesNotRecognizeSelector:]
#2  0x7fff8374e91f in ___forwarding___
#3  0x7fff8374aa68 in __forwarding_prep_0___
#4  0x7fff801ef636 in +[_NSPredicateUtilities max:]
#5  0x7fff800d4a22 in -[NSFunctionExpression expressionValueWithObject:context:]
#6  0x7fff865f2e21 in -[NSMappedObjectStore executeFetchRequest:withContext:]
#7  0x7fff865f2580 in -[NSMappedObjectStore executeRequest:withContext:]

I've seen this question on numerous forums elsewhere on the web, but no one has offered a workable solution. By popular request, I added my own code below. To explain slightly, my entity's name is Box and the property I'm trying to get the value of is "sortOrder", an Int 32 attribute.

NSManagedObjectContext *context = [MyLibrary managedObjectContext];

NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setEntity:[NSEntityDescription entityForName:@"Box"
                               inManagedObjectContext:context]];

// Specify that the request should return dictionaries.
[request setResultType:NSDictionaryResultType];

// Create an expression for the key path.
NSExpression *keyPathExpression = [NSExpression expressionForKeyPath:@"sortOrder"];

// Create an expression to represent the function you want to apply
NSExpression *expression = [NSExpression expressionForFunction:@"max:"
                                                     arguments:[NSArray arrayWithObject:keyPathExpression]];

// Create an expression description using the minExpression and returning a date.
NSExpressionDescription *expressionDescription = [[NSExpressionDescription alloc] init];

// The name is the key that will be used in the dictionary for the return value.
[expressionDescription setName:@"maxSort"];
[expressionDescription setExpression:expression];
[expressionDescription setExpressionResultType:NSInteger32AttributeType];

// Set the request's properties to fetch just the property represented by the expressions.
[request setPropertiesToFetch:[NSArray arrayWithObject:expressionDescription]];

// Execute the fetch.
NSError *error;
NSNumber *requestedValue = nil;
NSArray *objects = [context executeFetchRequest:request error:&error];
NSLog( @"objects: %@", objects );
if (objects != nil && [objects count] > 0) {
    requestedValue = [[objects objectAtIndex:0] valueForKey:@"maxSort"];
} else {
    [[NSApplication sharedApplication] presentError:error];
}

[expressionDescription release];
[request release];

NSLog( @"Max Sort Order: %@", requestedValue );
return requestedValue;
Community
  • 1
  • 1
Dov
  • 15,530
  • 13
  • 76
  • 177

6 Answers6

12

Apparently this is a known bug, that occurs when using an NSInMemoryStoreType data store. It seems it works fine using an NSSQLiteStoreType.

You can find the OpenRadar entry here

I filled a duplicate for this bug — I encourage people that encounter the same issue to do the same, to increase the likelihood this annoying behaviour gets documented (or even better, fixed).

Dov
  • 15,530
  • 13
  • 76
  • 177
Kemenaran
  • 1,421
  • 12
  • 11
  • This is useful information, but as mentioned in the question, I'm using `NSSQLiteStoreType`, not `NSInMemoryStoreType`. – Dov Dec 03 '12 at 19:07
  • Maybe when some autosaving is done, `NSInMemoryStoreType` is used. I am exactly in the same situation as you. Sometimes it crashes, sometimes not. It seems that when the program tries to reopen a closed document that has been auto-saved (where, by the way !) but not saved, it crashes. – Colas May 01 '13 at 16:17
3

When you have memory management issues (selectors being sent to the wrong instances is a sign of memory management issues), there are a number of things you can do:

  1. Re-read the Cocoa memory management rules and make sure that you're following them.
  2. Run the static analyser. This will often pick up places where you have neglected the memory management rules.
  3. Try using NSZombieEnabled to find out whether [and when] you are sending messages to unallocated instances.
dreamlax
  • 93,976
  • 29
  • 161
  • 209
  • I run the static analyzer very frequently, and NSZombieEnabled didn't show anything. I can re-read the memory management rules, though. – Dov Dec 08 '10 at 21:56
  • When you have Core Data issues (changing store type creating strange errors is a sign of Core Data issues), there is always a cookie cutter answer. – Léo Natan May 26 '13 at 13:23
1

This can also happen if a binding is not set correctly. For example, if you bind a matrix boolean value to "Content" instead of (or in addition to) "Selected Tag" in IB you can get this error.

If all else fails, disconnect all of your bindings and reconnect them one at a time to see which one is the culprit.

Nancy Poekert
  • 290
  • 4
  • 12
1

-[NSCFNumber count]: unrecognized selector sent to instance 0x100506a20 means, that you are calling count on a NSCFNumber object, but NSCFNumber doesnt have this method. So most likely count is send to a deallocated NSArray or NSSet object.

USE NSZombieEnabled = YES. It might tell you, what happens. Search SO for informations on how to set it.

vikingosegundo
  • 52,040
  • 14
  • 137
  • 178
  • `NSZombieEnabled` didn't tell me anything. Also, the selector is being sent from API code somewhere, not in anything I wrote (that I know of). – Dov Dec 08 '10 at 17:08
  • The system code could easily be sending it to an array, set, or dictionary that was over released by your code. After the over release, a new NSNumber is being allocated in the same spot the array, set, or dictionary used to be. – Jon Hess Dec 08 '10 at 18:21
  • If that's the case, how would I go about finding which object is causing the problem? Is there an Instrument or something that might help? – Dov Dec 08 '10 at 19:03
  • Yes, use the allocations instrument form instruments with the zombie option. Also consider trying the static analyzer. – Jon Hess Dec 09 '10 at 03:24
  • When I look through the history of the object that's receiving the unrecognized selector (which I found by the address in the error), it's way over-retained, not over-released. At its peak, it has a RefCt of 66, and it only goes down to 52 by the time the app quits. – Dov Dec 09 '10 at 13:09
0

You are using the key path: sortOrder in your path expression. At least for XML-Databases Core-Data cannot handle case-sensitive types. Change your path to sortorder (all lower-case)

You will probably stumble over further problems if you are using controller classes.

Dov
  • 15,530
  • 13
  • 76
  • 177
Rudi Rüssel
  • 439
  • 4
  • 13
  • Thanks for the input. I'm not using an XML backing store anymore, but that's good to know. – Dov Nov 28 '12 at 13:12
0

After experiencing exactly the same problem with exactly the same sample code, it finally worked for me after I put [request release] in.

stifin
  • 1,390
  • 3
  • 18
  • 28
  • No, it didn't work after all. However, I found this in the [documentation](http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSExpressionDescription_Class/NSExpressionDescription.html) and think it might be related to the problem but am too new to Core Data to be sure: "This method raises an exception if the receiverâs model has been used by an object graph manager." – stifin Jun 07 '11 at 02:49
  • I definitely stopped getting this error after removing `[request setResultType:NSDictionaryResultType];` altogether (not just replacing with `NSManagedObjectResultType` as you put in "Update 3". However, the value returned is sometimes inaccurate. It's like there's a lag there: when I repeatedly _increment the value, save to a new object, get max again, repeat_, sometimes 2 or 3 objects consecutively have not been incremented but have duplicates. – stifin Jun 08 '11 at 18:46