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

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];
}

Related

cannot init a class object : objective-C

I'm trying to make a simple subclass of CCNode, but I can't create the object.
It gives me the error "* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* +[ContentPane<0x206898> init]: cannot init a class object.'"
Here is my subclass of CCNode:
#import "ContentPane.h"
#implementation ContentPane{
int content[8][4];
CCSprite *_rockPath1;
CCSprite *_rockPath2;
}
- (id)init {
self = [super init];
if (self) {
CCLOG(#"ContentPane created");
}
return self;
}
#end
Here is where I try to initiate it:
- (void)didLoadFromCCB {
// tell this scene to accept touches
self.userInteractionEnabled = TRUE;
_counter = 0;
ContentPane *pane = [ContentPane init];
}
Couple things,
In Obj-c when you want to initialize an Object, you need to allocate space for it.
That is done using the alloc keyword.
so your ContentPane *pane = [ContentPane init];
turns into ContentPane *pane = [[ContentPane alloc] init];
Also, whatever tutorial you are following, Stop... the way you have declared your variables we call them (iVars) is a very old fashioned way of doing things, they should really be properties. and Boolean values are represented by YES and NO not TRUE and FALSE
If you are here just like me wondering why you code is crashing.
[NSArray init];
should be :
[[NSArray alloc] init];
or
[NSArray array];
You crash could caused by any other class here NSArray here is for reference only.

message sent to deallocated instance ,,, [__NSArrayI respondsToSelector:]

I have this implementation file with aNSArray object userIDs
NSArray *userIDs;
NSInteger friendID;
#implementation TableViewController
-(void)reciveFriendsIDs:(NSArray *)array
{
userIDs = [NSArray arrayWithArray:array];
}
-(NSString *)getFriendId
{
return [userIDs objectAtIndex:friendID];
}
.
.
.
#end
and the method -(NSString *)getFriendId call it from another class like this :
TableViewController *tableController = [[TableViewController alloc]init];
NSString *fid = [tableController getFriendId];
But I am having an error said "-[__NSArrayI respondsToSelector:]: message sent to deallocated instance 0x20320200" and the compiler indicate the error in this line:
return [userIDs objectAtIndex:friendID];
You are allocating the NSArray with arrayWithArray static method.
In this way it's getting added in the auto release pool and the retain count will be 0.
Either retain it or manually alloc it with [[NSArray alloc] init]
I was getting the same exception on line
if(self.arrTypes != nil)
cause of the following line being used at a different place in code
[self.arrTypes release];
and replacing this code with
self.arrTypes = nil;
resolved the issue.

Why is it that sending any selector to a Nil object does nothing, but sending an "invalid" selector to any NSObject raises an exception?

Does anyone know why NextStep/Apple decided to take the "convenient method" of doing nothing when passing a Nil object a message, but the "Java method" of raising an exception when passing an instantiated object an invalid selector?
For example,
// This does "nothing"
NSObject *object = Nil;
[object thisDoesNothing];
object = [[NSObject alloc] init];
// This causes an NSInvalidArgumentException to be raised
[object thisThrowsAnException];
So on one hand, we have the convenience of not having to check for Nil (assuming we don't care too much about the result of the method call)--but on the other hand we have to check for an exception if our object doesn't respond to a method?
If I'm not sure if the object will respond, I either have to:
#try {
[object thisThrowsAnException];
} #catch (NSException *e){
// do something different with object, since we can't call thisThrowsAnException
}
Or,
if([object respondsToSelector:#selector(thisThrowsAnException)]) {
[object thisThrowsAnException];
}
else {
// do something different with object, since we can't call thisThrowsAnException
}
(The latter is probably the better way to do it, since if object is Nil, the selector would NOT raise an exception, thus your code might not behave the way you want it to).
My question is:
WHY did Apple decide to implement it this way?
Why not have the unrecognized selector call to an instantiated object not raise an exception?
Alternatively, why not have the Nil object raise an exception if you try to call a method on it?
I can't fully answer your question, but I can answer part of it. Objective-C allows you to send a message to nil because it makes code more elegant. You can read about this design decision here, and I will steal its example:
Let's say you want to get the last phone number that some person dialed on her office phone. If you can't send messages to nil, you have to write it like this:
Office *office = [somePerson office];
// Person might not have an office, so check it...
if (office) {
Telephone *phone = [office telephone];
// The office might not have a telephone, so check it...
if (phone) {
NSString *lastNumberDialed = [phone lastNumberDialed];
// The phone might be brand new, so there might be no last-dialed-number...
if (lastNumberDialed) {
// Use the number, for example...
[myTextField setText:lastNumberDialed];
}
}
}
Now suppose you can send messages to nil (and always get nil back):
NSString *lastNumberDialed = [[[somePerson office] telephone] lastNumberDialed];
if (lastNumberDialed) {
[myTextField setText:lastNumberDialed];
}
As for why sending an unrecognized selector to an object raises an exception: I don't know for sure. I suspect that it's far more common for this to be a bug than to be harmless. In my code, I only want an unrecognized selector to be silently ignored when I need to send an optional protocol message (e.g. sending an optional message to a delegate). So I want the system to treat it as an error, and let me be explicit in the relatively rare case when I don't want it to be an error.
Note that you can tinker (to some extent) with the handling of unrecognized selectors in your own classes, in a few different ways. Take a look at the forwardingTargetForSelector:, forwardInvocation:, doesNotRecognizeSelector:, and resolveInstanceMethod: methods of NSObject.
From the good ol' documentation:
In Objective-C, it is valid to send a message to nil—it simply has no
effect at runtime.
As for the other problem of the unrecognized selector behavior, an old implementation file of NSObject (from the MySTEP library) shows that the culprit is the NSObject method -doesNotRecognizeSelector:, which looks a bit as follows:
- (void) doesNotRecognizeSelector:(SEL)aSelector
{
[NSException raise:NSInvalidArgumentException
format:#"NSObject %#[%# %#]: selector not recognized",
object_is_instance(self)?#"-":#"+",
NSStringFromClass([self class]),
NSStringFromSelector(aSelector)];
}
Which means that ObjC methods could feasibly be tinkered with so that they do not in fact have to raise an error. Which means the decision was entirely arbitrary, just like the decision to switch to "method-eating" messages to nil. A feat which can be done through method swizzling NSObject (wholly dangerous, as it will raise an EXC_BAD_ACCESS, or EXC_I386_BPT on mac, but at least it doesn't raise an exception)
void Swizzle(Class c, SEL orig, SEL new)
{
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
method_exchangeImplementations(origMethod, newMethod);
}
-(void)example:(id)sender {
Swizzle([NSObject class], #selector(doesNotRecognizeSelector:), #selector(description));
[self performSelector:#selector(unrecog)];
}
The category:
#implementation NSObject (NoExceptionMessaging)
-(void)doesNotRecognizeSelector:(SEL)aSelector {
NSLog(#"I've got them good ol' no exception blues.");
}
#end
For everyone's amusement, due to the discussion CodaFi and I were having, here's a quickly-hacked-together way to eat normally unresponded-to messages and have them return nil:
#interface EaterOfBadMessages : NSObject
#end
#implementation EaterOfBadMessages
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
{
NSMethodSignature * sig = [super methodSignatureForSelector:aSelector];
if( !sig ){
sig = [NSMethodSignature signatureWithObjCTypes:"##:"];
}
return sig;
}
- (void)forwardInvocation:(NSInvocation *)anInvocation
{
id nilPtr = nil;
[anInvocation setReturnValue:&nilPtr];
}
#end
int main(int argc, const char * argv[])
{
#autoreleasepool {
EaterOfBadMessages * e = [[EaterOfBadMessages alloc] init];
// Of course, pre-ARC you could write [e chewOnThis]
NSLog(#"-[EaterOfBadMessages chewOnThis]: %#", [e performSelector:#selector(chewOnThis)]);
}
return 0;
}
Please don't use this in real life.

What is the cause of error by using NSPredictate?

I used the NSPredictate Class, but the following error has occurred.
I Can't know the reason.
Why does occur following error?
Follow is source code.
#import "Predictate.h"
#implementation Predictate
#synthesize dictate;
-(id)init{
if ((self = [super init])) {
}
return self;
}
- (void)Predictate{
dictate = [[NSMutableArray alloc]initWithObjects:#"AAA",#"BBB",#"CCC", nil];
NSPredicate *test = [NSPredicate predicateWithFormat:#"dictate like 'AAA'"];
NSMutableArray *result = [dictate filteredArrayUsingPredicate:test];
NSLog(#"%#",result);
}
-(void)dealloc{
[dictate release];
[super dealloc];
}
#end
Error message is below.
2012-01-02 00:57:39.972 filter[1750:707] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFConstantString 0x100002290> valueForUndefinedKey:]: this class is not key value coding-compliant for the key dictate.'
You're using NSPredicate to filter an array of string objects, but are using dictate like 'AAA'. The predicate will have absolutely no idea what this dictate means.
You will want to replace dictate with SELF, so that it becomes "SELF like 'AAA'"

Unrecognized selector sent to instance - why?

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?