Objective-C: Why this function name caused a warning? - objective-c

This is the original header file:
#interface TestDataHelper : NSObject {
}
+(void) populateTestData:(NSManagedObjectContext*) managedObjectContext;
+(void) testPopulateTestData:(NSManagedObjectContext*) managedObjectContext;
#end
When I compile this file, I got this warning:
method definiton not found
for testPopulateTestData
When I ignore the warning and run the app in iphone simulator, I got a runtime exception:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[TestDataHelper testPopulateTestData:]: unrecognized selector sent to class 0x104d8'
Rename the method to 'test' alone seems to solve the problem
What is special about testXXX method name?
EDIT: implementation is there and done. Renaming the method name (in both .h and .m) removes the warning, and the final app works.
EDIT 2:
Here is the implementation of the function test (originally named as testPopulatedTestData):
+(void) test:(NSManagedObjectContext*) managedObjectContext {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Stock" inManagedObjectContext:managedObjectContext];
[request setEntity:entity];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"name" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[sortDescriptors release];
[sortDescriptor release];
NSError *error = nil;
NSMutableArray *mutableFetchResults = [[managedObjectContext executeFetchRequest:request error:&error] mutableCopy];
NSEnumerator *e = [mutableFetchResults objectEnumerator];
id object;
while (object = [e nextObject]) {
// do something with object
Stock* fc = (Stock*) object;
NSLog(#"get a fc %s", [[fc name] description]);
}
}

The error message is telling you that you've declared a method in your header file that you never implemented anywhere. The runtime error is telling you the same thing - you've sent the selector testPopulateTestData to the class TestDataHelper but it was never implemented.

Related

Core Data app crashes on saving

I got the following error [context save:&error]. How should I fix?
unrecognized selector sent to class
* -[NSKeyedArchiver dealloc]: warning: NSKeyedArchiver deallocated without having had -finishEncoding called on it.
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[TempObject encodeWithCoder:]:
unrecognized selector sent to class'
Here the code I'm using.
NSManagedObjectContext *context = [self.fetchedResultsController managedObjectContext];
PostRequest *postRequestObject = (PostRequest *)[NSEntityDescription insertNewObjectForEntityForName:#"PostRequest" inManagedObjectContext:context];
DummyClass *request = OtherClassObject;
postRequestObject.request = request;
// request is attribute with type transformable
NSLog(#"requestpost data -> %#",postRequestObject.request);
NSError *error = nil;
if (![context save:&error]) {
// Replace this implementation with code to handle the error appropriately.
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
#pragma mark - private method
- (NSFetchedResultsController *)fetchedResultsController
{
if (_fetchedResultsController != nil)
{
return _fetchedResultsController;
}
NSFetchRequest *fetchRequest = [[[NSFetchRequest alloc] init] autorelease];
// Edit the entity name as appropriate.
NSEntityDescription *entity = [NSEntityDescription entityForName:#"PostRequest" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:80];
// Edit the sort key as appropriate.
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"status" ascending:NO];
NSArray *sortDescriptors = #[sortDescriptor];
[sortDescriptor autorelease];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"root"] autorelease];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
NSError *error = nil;
if (![self.fetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return _fetchedResultsController;
}
The error message says that you have a class named TempObject, that you're trying to call encodeWithCoder: on it, and that this class does not implement that method. That's a crashing bug, as you're seeing.
It seems that you have a transformable Core Data attribute somewhere, and that you're assigning an instance of TempObject to this attribute. I don't know where that is. Your code snippet mentions a transformable attribute, but you don't use TempObject in the code. I can't tell if this code is not actually the cause of the crash or if you changed the name by hand for some reason.
Anyway, when you have a transformable attribute, you must do one of two things:
Make your class conform to NSCoding. You said in a comment that you did, but your error message says that you didn't-- or at least, that you didn't finish the job. NSCoding defines two methods, initWithCoder: and encodeWithCoder:, and your class must implement both of them.
Create a custom NSValueTransformer subclass that can convert your object to/from NSData, and configure your Core Data model to use this. Apple provides a couple of really good (but simple) examples of how to do this.
Anything you assign to a transformable attribute must do one of these. Which one is up to you.
It seems that you're trying to do #1 but haven't finished the job. Make sure that your class conforms to NSCoding.

Compiler error "use of undeclared identifier" when I remove my #synthesize statements

With the latest LLVM build, the requirement for synthesizing properties has been removed.
Therefore I was able to remove all my #synthesize statements except for the ones for NSFetchedResultsController. Does anyone know why the compiler is warning me when I remove the #synthesize fetchedResultsController; line?
Error:
Use of undeclared identifier "fetchedResultsController", did you mean _fetchedResultsController?
This is my code:
#property (nonatomic, strong) NSFetchedResultsController *fetchedResultsController;
#synthesize fetchedResultsController;
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController) {
return fetchedResultsController;
}
if (!self.managedObjectContext) {
self.managedObjectContext = [(MyAppDelegate *)[[UIApplication sharedApplication] delegate] managedObjectContext];
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Session" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setPredicate: self.predicate];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"timeStamp" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
fetchedResultsController= [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:nil];
fetchedResultsController.delegate = self;
NSError *error = nil;
if (![fetchedResultsController performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return fetchedResultsController;
}
When you don't put an #synthesize in your code, the instance variable created to back the property is named _propertyName. You are referring to the instance variable fetchedResultsController which no longer exists after you remove the #synthesize. Instead, change all references to fetchedResultsController to _fetchedResultsController.
Because the default synthesized variable is _fetchedResultsController not fetchedResultsController
The property fetchedResultsController is automatically synthesized to _fetchedResultsController, and this happens for every synthesized variable.
You should synthesize it explicitly to change its name.

Is this function producing any memory leak?

+ (NSArray *) fetchAllContactsInContext:(NSManagedObjectContext *)a_context
{
NSFetchRequest *_request = [[NSFetchRequest alloc] init];
[_request setEntity:[NSEntityDescription entityForName:#"Contact" inManagedObjectContext:a_context]];
NSSortDescriptor *_sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:YES];
NSArray *_sortDescriptors = [[NSArray alloc] initWithObjects:_sortDescriptor, nil];
[_request setSortDescriptors:_sortDescriptors];
NSError *_fetchError=nil;
NSArray *_results = [[NSArray alloc] initWithArray:[a_context executeFetchRequest:_request error:&_fetchError]];
[_sortDescriptor release];
[_sortDescriptors release];
[_request release];
if (_fetchError){
NSLog(#"Contact - Error fetching contacts %#", [_fetchError localizedDescription]);
}
[_fetchError release];
return [_results autorelease];
}
I wanna ask, Is this function leaking memory? Actually Instruments is saying that this function is leaking hell lot of memory.
Can you please help me resolving the memory issue?
If you need to see where retains, releases and autoreleases occur for an object use instruments:
Run in instruments, in Allocations set "Record reference counts" on on (you have to stop recording to set the option). Cause the problem code to run, stop recording, search for there ivar of interest, drill down and you will be able to see where all retains, releases and autoreleases occurred.
Here is a simplifies version using ARC for iOS 4.3 and up:
+ (NSArray *) fetchAllContactsInContext:(NSManagedObjectContext *)aContext {
NSFetchRequest *request = [NSFetchRequest fetchRequestWithEntityName:#"Contact"];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"lastName" ascending:YES];
[request setSortDescriptors:#[sortDescriptor]];
NSError *fetchError;
NSArray *results = [aContext executeFetchRequest:request error:&fetchError];
if (results == nil){
NSLog(#"Contact - Error fetching contacts %#", [fetchError localizedDescription]);
}
return results;
}
Why [_fetchError release]; is there?
And Why don't you use ARC?
Try to refactor this code into ARC.

NSFetchedResultsController always returns NSManagedObject objects instead of custom

I am using CoreData and have an Entity ContactList defined, which I created using the XCode xcdatamodel tool (or whatever you call that built-in thing:). I also set the Entity's Class name to "ContactList". I then used rentzsch's mogenerator (http://github.com/rentzsch/mogenerator) to generate my custom class files and added the simple method "toString" to my ContactList class.
The fetchedResultsController callback is pretty much standard and looks as follows:
- (NSFetchedResultsController *)fetchedResultsController {
if (fetchedResultsController_ != nil) {
return fetchedResultsController_;
}
NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"ContactList" inManagedObjectContext:self.managedObjectContext];
[fetchRequest setEntity:entity];
[fetchRequest setFetchBatchSize:20];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"timeStamp" ascending:NO];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[fetchRequest setSortDescriptors:sortDescriptors];
NSFetchedResultsController *aFetchedResultsController = [[NSFetchedResultsController alloc] initWithFetchRequest:fetchRequest managedObjectContext:self.managedObjectContext sectionNameKeyPath:nil cacheName:#"Root"];
aFetchedResultsController.delegate = self;
self.fetchedResultsController = aFetchedResultsController;
[aFetchedResultsController release];
[fetchRequest release];
[sortDescriptor release];
[sortDescriptors release];
NSError *error = nil;
if (![fetchedResultsController_ performFetch:&error]) {
NSLog(#"Unresolved error %#, %#", error, [error userInfo]);
abort();
}
return fetchedResultsController_;
}
Now, when I start my application and try to call that method on a "ContactList" object, which in turn I get from a NSFetchedResultsController, I get
ContactList *contactList = (ContactList *) [self.fetchedResultsController objectAtIndexPath:indexPath];
[contactList toString];
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSManagedObject toString]: unrecognized selector sent to instance 0x6af7bf0'
As the message shows, somehow the NSFetchedResultsController does not return a "ContactList" object, but a more general NSManagedObject instead.
Does anybody know why and how to resolve this???
I had this same problem - Caused because I had previously renamed the Entity's Managed Object subclass. In the Data Modeler, make sure in the Inspector for the entity, both the "Name" and the "Class" are set correctly.
Ok, I figured this it out.
The problem was that the mogenerator script did not add its generated source files to the project's compile target. This way the classes never got compiled and included (I wonder how it worked without any model object classes :)
After adding the .xcdatamodel file to the Target (RightClick on .xcdatamodel file -> Targets -> check your project) everything works now.
For further info go here

How can I shuffle an NSArray?

All examples I find on shuffling arrays are for NSMutableArrays. Copying an NSArray to an NSMutable array, shuffling, then copying back always crashes the application. Is it even possible to shuffle an NSArray?
Anything in objective-c similar to Collections.shuffle() (Java)?
Edit
static NSUInteger random_below(NSUInteger n) {
NSUInteger m = 1;
do {
m <<= 1;
} while(m < n);
NSUInteger ret;
do {
ret = random() % m;
} while(ret >= n);
return ret;
}
- (NSArray *)loadAllData{
XYZAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSManagedObjectContext *managedObjectContext = appDelegate.managedObjectContext;
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:#"Quote" inManagedObjectContext:managedObjectContext];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:#"id" ascending:YES];
NSArray *sortDescriptors = [[NSArray alloc] initWithObjects:sortDescriptor, nil];
[request setSortDescriptors:sortDescriptors];
[request setEntity: entity];
NSError *myError;
NSArray *theResults = [managedObjectContext executeFetchRequest:request error:&myError];
if (theResults == nil) {
NSLog(#"Testing: No results found");
}else {
NSLog(#"Testing: Results found.");
}
[request release];
[sortDescriptors release];
for(NSUInteger i = [theResults count]; i > 1; i--) {
NSUInteger j = random_below(i);
[theResults exchangeObjectAtIndex:i-1 withObjectAtIndex:j];
}
return theResults;
}
warning: 'NSArray' may not respond to '-exchangeObjectAtIndex:withObjectAtIndex:' which crashed the application.
error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[_PFArray exchangeObjectAtIndex:withObjectAtIndex:]: unrecognized selector sent to instance 0x3d35a40
OK. I think I see a problem. Always look at the error message. I thought you said that you were using NSMutableArrays in this function?
NSArray *theResults = [managedObjectContext executeFetchRequest:request error:&myError];
Change that to
NSMutableArray *theResults = [[managedObjectContext executeFetchRequest:request error:&myError] mutableCopy];
Tell me if it works, and if it doesn't, I'll try and help.
Some more info:
-exchangeObjectAtIndex:withObjectAtIndex:
is a method for a NSMutableArray. You were using a NSArray, they're different classes (NSMutableArray is a subclass (and adds methods that mean you can modify it) of NSArray).