Unrecognized selector sent to instance - why? - objective-c

OK so I have a code with an class object called "game". Every frame (60 FPS) I update that object with function that gets a string. After like 5 seconds of running the game I'm getting the unrecognized selector sent to instance error.
The update:
[game updatePlayersAndMonsters:#"0" monsters:#"0"];
The function:
-(void)updatePlayersAndMonsters:(NSString*)players monsters:(NSString*)monsters {
CCLOG(#"%#.%#", players, monsters);
}
I don't understand what's going on.
The error:
2011-07-03 12:13:19.175 app[65708:207] -[NSCFString updatePlayersAndMonsters:monsters:]: unrecognized selector sent to instance 0xc4e95b0
2011-07-03 12:13:19.176 app[65708:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSCFString updatePlayersAndMonsters:monsters:]: unrecognized selector sent to instance 0xc4e95b0'
What should I do? Thanks. Also IDK if any other details you need, so just write if I forget something, I just don't have an idea.
UPDATE:
Gmae is object of class GameNode:
+(id) GmameNodeWithMapID:(int)MapID_ scene:(SomeScene*)MainScene_ players:(NSString*)Cplayers_ monsters:(NSString*)Cmonsters_ monsterCount:(NSString*)monsterCount_
{
return [[[self alloc] GmameNodeWithMapID:MapID_ scene:MainScene_ players:Cplayers_ monsters:Cmonsters_ monsterCount:monsterCount_] autorelease];
}
-(id) GmameNodeWithMapID:(int)MapID scene:(SomeScene*)MainScene players:(NSString*)Cplayers monsters:(NSString*)Cmonsters monsterCount:(NSString*)monsterCount
{
if( (self=[super init])) {
I create it with:
game = [GameNode GmameNodeWithMapID:ChoosenMapID scene:self players:Thing[5] monsters:Thing[6] monsterCount:Thing[4]];
UPDATE 2
I create the SomeScene:
+(id) scene {
CCScene *s = [CCScene node];
id node = [SomeScene node];
[s addChild:node];
return s;
}
-(id) init {
if( (self=[super init])) {
I use it:
[[CCDirector sharedDirector] replaceScene: [CCTransitionRadialCW transitionWithDuration:1.0f scene:[LoginScene scene]]];

Since you imply that the update function [game updatePlayersAndMonsters:#"0" monsters:#"0"]; is called for the first 5 seconds of your game and then you get the error, my guess is that the game object is not correctly retained, so it gets deallocated and the successive attempt of sending a message to it fails because some NSString object has been reusing its memory (and it does not have a updatePlayersAndMonsters:monsters selector).
Please share how game is created (alloc/init) and how it is stored in your classes to help you further.
Activating NSZombies tracking could also help to diagnose this.
EDIT: after you adding the code
It seems to me that in the line:
game = [GameNode GmameNodeWithMapID:ChoosenMapID scene:self players:Thing[5] monsters:Thing[6] monsterCount:Thing[4]];
you are setting either a local variable or an ivar to your autoreleased GameNode.
Now, since you are not using a property, nor I can see any retain on your autoreleased GameNode, my hypothesis seems confirmed. Either assign to a retain property:
self.game = [GameNode ...];
being game declared as:
#property (nonatomic, retain)...
or do a retain yourself:
game = [[GameNode GmameNodeWithMapID:ChoosenMapID scene:self players:Thing[5] monsters:Thing[6] monsterCount:Thing[4]] retain];

'NSInvalidArgumentException', reason: '-[NSCFString updatePlayersAndMonsters:monsters:]: means tht you are trying to send updatePlayersAndMonsters to a String object. Are you reassigning game to point to something else?

Related

How to catch unrecognized selector sent to instance exception?

I am getting after some time unrecognized selector sent to instance exception. When i get this i want just skip it and my app should work.
However i don't know how to catch. As this don't catch:
#property(nonatomic,retain) UIButton *button;
#try{
if(button.currentBackgroundImage == nil){//rises exception
}
}#catch(NSException *e){
}
How i could handle this ?
Thanks.
The technique I use and see often is: instead of catching the exception, check if the object responds to the selector:
if(![button respondsToSelector:#selector(currentBackgroundImage)] || button.currentBackgroundImage == nil) {
// do your thing here...
}
If you are getting this exception, it means there is a design flaw, a bug in your code. Patching it by ignoring the exception is not the right thing to do. Try to pin down why you are sending the wrong message to the wrong object instead. Your code will become more robust and maintainable.
Also, sometimes you get this exception when the object originally was of the right type, but is halfway in the process of being deallocated. Watch out!
If you still want to bypass the exception, read Apple's docs where it explains the multi-step process by which messages are bound to method implementations at run time. There is at least two places where you can catch it by overriding NSObject's default behavior.
I understand the answers telling you to prevent the unrecognized selector since that is the preferred method.
But in the case where you do not have that option (such as in my case, Cocoa internals messing up further down the call stack) you can indeed catch the unrecognized selector as you tried.
Proof of concept code:
// Do a really bad cast from NSObject to NSButton
// to get something to demonstrate on
NSButton *object = (NSButton*)[[NSObject alloc] init];
#try{
// Log the description as the method exists
// on both NSObject and NSButton
NSLog(#"%#", [object description]);
// Send an unrecognized selector to NSObject
[object bounds];
} #catch(NSException *e){
NSLog(#"Catch");
} #finally {
NSLog(#"Finally");
}
// Print the description to prove continued execution
NSLog(#"Description again: %#", [object description]);
Output:
2019-02-26 14:11:04.246050+0100 app[46152:172456] <NSObject: 0x60000000a6f0>
2019-02-26 14:11:04.246130+0100 app[46152:172456] -[NSObject bounds]: unrecognized selector sent to instance 0x60000000a6f0
2019-02-26 14:11:04.246226+0100 app[46152:172456] Catch
2019-02-26 14:11:04.246242+0100 app[46152:172456] Finally
2019-02-26 14:11:04.246258+0100 app[46152:172456] Description again: <NSObject: 0x60000000a6f0>
As you can see the exception is still logged to the console, but the code execution continues.

Strange BAD_ACCESS error

This may sound a newbie question however I'm new iOS dev,
recently I've switched to ARC and have got following issue in my code. I've implemented a class with following init method
- (id)init
{
self = [super init];
if (self) {
TokenManager* tokenManager = [[TokenManager alloc] initWithApikey:<my valid token>];
mRequest = [[GeoCodingRequest alloc] initWithApikey:apiKey withOptions:nil tokenManager:tokenManager];
mRequest.delegate = self;
}
return self;
}
where mRequest in interface is declared like this __strong GeoCodingRequest* mRequest;
In my other method of the same class I send a message to mRequest like this
[mRequest findObject:<some valid array> around:<some valid location> withDistance:<some valid radius>];
When the message is sent to object app crashes with following message
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString appendRequestWithToken:]: unrecognized selector sent to instance 0x8974640'
findObject: around: withDistance: - is a method from public library, so I've not access to its implementation.
Please help me to understand why this crash happens ?!
I guess it is coming from ARC _strong/_weak qualifier usage or smth.
The message means that mRequest has been deallocated has that a string is now using the memory that had previously been allocated for mRequest.
You should run your app with Zombies enabled to understand when mRequest gets deallocated.
It looks like the tokenManager isn't retained by the request (which is a bug in the library). As it isn't retained anywhere, the tokenManager is deallocated and a new object (here an instance of NSString) may be allocated at the same place.
You need to store the tokenManager in a strong instance variable (just as mRequest) in order to retain it as long as the request needs it.
if you have any weak references try to use
MyObject * strongMyObject = weakMyObject;
if(strongMyObject){
NSLog(#"This is not released");
}
It's a good practice when you have weak references. Try this.

EXC_BAD_ACCESS on NSManagedObjectContext save method inside NSOperation and ARC, why?

I have found some problems when saving NSManagedObjectContext inside NSOperation with turned on ARC. Without ARC everything was fine before. It is always gives EXC_BAD_ACCESS during saving. The code looks like this:
//on the main thread
-(void)someFunc
{
array = ... //fetching an array of entities from a core data
for(SomeEntity * obj in array)
{
NSSomeOperation * op = [[NSSomeOperation alloc] initWithValue:[obj someField]];
//start an operation
}
}
//NSSomeOperation implementation
//...
- (void)main {
//some code
NSError * error = nil;
[mainContext lock];
if (![mainContext save:&error]) { //<--- HERE EXC_BAD_ACCESS
//process error
}
[mainContext unlock];
//some code
}
//...
Using of [mainContext setRetainsRegisteredObjects:YES] and objectWithID don't resolve this issue.
EXC_BAD_ACCESS (code=1)
EXC_BAD_ACCESS (code=13)
-[__NSCFType contextDidSave:]: unrecognized selector sent to instance 0x7fc5c505d940
An observer of NSManagedObjectContextDidSaveNotification illegally threw an exception.
Objects saved = {
inserted = "{(\n)}";
updated = "{(\n <SomeEntity: 0x7fc5c55b6220> (entity: SomeEntity; id: 0x7fc5c5052b20 ... )}"; }
and exception = -[__NSCFType contextDidSave:]: unrecognized selector sent to instance 0x7fc5c505d940 with userInfo = (null)
I use a separate managed object context and fetch my managed objects inside this NSOperation.
Maybe it is something related to Core Data bugs or ARC? Maybe ARC cleans some of objects, that must be saved?
Because, without ARC everything was fine, all worked. When I turned on ARC - EXC_BAD_ACCESS.
Does anyone know why it occurs?
Maybe ARC deallocates some object that receives NSManagedObjectContextDidSaveNotification and this causes the exception?
I had something similar, and fixed it by making sure to removeObserver: before the object gets deallocated.
Note that the CoreData exception actually hides the notification center exception, so you don't get to see it.

UIImage setter NSInvalidArgumentException

have a problem with object setters in a class.
I have the class GEOImage, where things like description, title etc. will be saved according
to an image.
#interface GEOImage : UIImage
{
NSString *title;
NSString *imgDescription;
NSString *latitude;
NSString *longitude;
NSDictionary *editInfo;
}
#property (nonatomic, copy) NSString *title, *imgDescription, *latitude, *longitude;
#property (nonatomic, copy) NSDictionary *editInfo;
#end
Now i try to store a description out of another class:
self.chosenImage.imgDescription = #"description";
where chosenImage is of type GEOImage.
But i get the error:
-[UIImage setTitle:]: unrecognized selector sent to instance 0x939d220
2011-12-05 10:59:40.621 GeoPG[511:17c03] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIImage setTitle:]: unrecognized selector sent to instance 0x939d220'
If I'm looking in the debugger, the chosenImage is not NULL, and its been displayed correct in an image view.
Greets
s4lfish
We can safely infer that chosenImage is not nil; if it were nil, sending it a message would simply do nothing, not crash.
(Also, I'm assuming that you meant title rather than imgDescription in your usage sample, or that you implemented setImgDescription: to set the title in turn.)
There are two possibilities:
Dead object
You created the image you stored to chosenImage as a GEOImage, but then it died while you were holding on to it. Subsequently, a UIImage (as identified in the exception message) was created at the same address, so the pointer you still hold now points to a UIImage. You sent a message to it that only works on GEOImages, but it's only a UIImage, so it doesn't respond to the message, which is the exception.
The cause of an object dying while you're holding it is that either you didn't retain it somewhere where you should have, or you released it somewhere where you shouldn't have. Or possibly both.
Run your app under Instruments with the Zombies template. It will raise a flag when you hit this crash, and you can then investigate by clicking the button in that flag. Look at all of the Release and Autorelease events, starting from the end, to find the one that shouldn't be there; then, if the release itself is unwarranted, take it out, or if it should be balanced by a previous retain, put one of those in.
One possible cause of the crash is that you declared the chosenImage property as assign, but you should have declared it as retain/strong. If this is the problem, your Instruments findings will support it.
Long-term, you should convert to ARC, which eliminates 90% of the cases where this problem could happen.
You never created a GEOImage in the first place
Just because you declared that chosenImage will hold a pointer to a GEOImage doesn't mean it does. You can assign any object pointer there, and in many cases, the compiler doesn't know if it isn't actually a GEOImage.
(They introduced a feature called “related result types” in a future version of Clang that should make this much less likely.)
At a guess, I'd say you're doing something like this:
self.chosenImage = [GEOImage imageNamed:#"blah blah blah"];
or this:
self.chosenImage = [imagePicker takePicture];
There is no reason to expect takePicture to return a GEOImage (how should it know that's what you want?), and it's likely that +[UIImage imageNamed:] (assuming you simply inherit it) won't, either. Unless you create a GEOImage instance yourself, using alloc and an initializer, you cannot assume that any UIImage you get will be a GEOImage.
The solution is to make it easy to create a GEOImage from a UIImage (which will involve wrapping this method), and then do that.
Once you have a live (not dead) GEOImage (not UIImage) in your chosenImage property, it will work.
In fact, it was like Peter said: I never created an GEOImage. I now I create the GEOImage like this:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
UIImage *image = [info valueForKey:#"UIImagePickerControllerOriginalImage"];
NSURL *imgURL = [info valueForKey:#"UIImagePickerControllerMediaURL"];
CGImageRef imageRef = [image CGImage];
[self createGEOImage:imageRef info:info imageURL:imgURL];
}
And the method called with the imageRef:
- (void)createGEOImage:(CGImageRef*)imageRef info:(NSDictionary*)info imageURL:(NSURL*)imgURL{
GEOImage *geoImage = [[GEOImage alloc]initWithCGImage:imageRef];
geoImage = info;
geoImage = imgURL;
}
Thanks for your help!

Objective C/NSMutableDictionary - [NSCFSet objectForKey:]: unrecognized selector

I do not understand what I am doing wrong. I have a dictionary as a property of a singleton class:
#interface CABResourceManager : NSObject
{
....
NSMutableDictionary* soundMap;
}
#property (retain) NSMutableDictionary *soundMap;
Then I add an object to this dictionary in one class method:
+ (void)loadSoundFromInfo:(ABSoundInfo)sound
{
static unsigned int currentSoundID = 0;
CABSound* newSound = [[CABSound alloc] initWithInfo:(ABSoundInfo)sound soundID:++currentSoundID];
[[CABResourceManager sharedResMgr].soundMap setObject:newSound forKey:sound.name];
}
And try to get it in another method:
+ (ALuint)playSoundByName:(NSString*)name
{
NSMutableDictionary* map = [CABResourceManager sharedResMgr].soundMap;
CABSound *sound = [map objectForKey:name]; // here comes the exception
and the app exits on exception by that.
2011-03-27 20:46:53.943 Book3HD-EN[5485:207] *** -[NSCFSet objectForKey:]: unrecognized selector sent to instance 0x226950
2011-03-27 20:46:53.945 Book3HD-EN[5485:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException'
I guess it might have something with memory management, but hier it looks clear for me: CABSound object is retained in dictionary by doing setObject(), it should not be released at this time.
I'd check that soundMap is properly initialized. It looks like soundMap is a bad pointer at the time you get the error. It might happen to be nil in +loadSoundFromInfo, which wouldn't produce an error right away.
Make sure that you've initialized your soundMap in designated initializer:
// - (id) init... or something else
soundMap = [[NSMutableDictionary alloc] init];
Dont forget to override default dealloc implementation:
// class implementation file
- (void)dealloc {
[soundMap release];
//...release other objects you own...
[super dealloc];
}