Can't add a UIViewController subclass to NSDictionary - objective-c

I wan't to add a subclass of UIViewController to a NSMutableDictionary which should be no problem since UIViewController is a NSObject.
This is my code:
NSArray *requestingPathes = [[NSArray alloc] initWithObjects:indexPath, nil];
requestingPair = [[NSMutableDictionary alloc] initWithObjectsAndKeys:requestingPathes, dele, nil];
The app crashes when the delegate "dele" (which happens to be the mentioned subclass) is used to initialize the Dictionary "requestingPair".
The error is:
-[MainViewController copyWithZone:]: unrecognized selector sent to instance 0x7446b30
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[MainViewController copyWithZone:]: unrecognized selector sent to instance 0x7446b30
0x7446b30 is the address of the subclass "MainViewController.
Why is this happening?

-initWithObjectsAndKeys: expects a list of objects and keys, in that order—alternating object, key, object, key, nil. What you’re doing is trying to give it your dele object as a key from which the value requestingPathes can be retrieved; NSDictionary objects copy their keys when you set them, and your view controller doesn’t support being copied, so that’s failing. Presumably what you want to do is something more like this:
requestingPair = [[NSMutableDictionary alloc] initWithObjectsAndKeys:requestingPathes, #"paths", dele, #"delegate", nil];
You can then retrieve the delegate object by calling [requestingPair objectForKey:#"delegate"] and the paths with [requestPair objectForKey:#"paths"].

Your dictionary key must conform to the NSCopying protocol, which UIViewController (and your MainViewController) doesn't.
Do you want dele to be the key or the value? It's currently the key.

Related

[__NSArrayI replaceObjectAtIndex:withObject:]: unrecognized selector sent to instance

I have a NSMutableArray, which I need to chance its values, but I have this error:
[__NSArrayI replaceObjectAtIndex:withObject:]: unrecognized selector sent to instance 0x5291db0
This is the declaration of my NSMutableArray:
NSMutableArray *selectedOptions = [NSArray arrayWithObjects:[NSNumber numberWithInteger:0], nil];
Then, I'm using replaceObjectAtIndex method, of this way:
[self.selectedOptions replaceObjectAtIndex:0 withObject:[NSNumber numberWithInteger:1]];
But I get, that error, and I'm using NSMutableArray.
Thanks
You are creating a regular non-mutable NSArray. Your code should be
NSMutableArray *selectedOptions = [NSMutableArray arrayWithObjects:[NSNumber numberWithInteger:0], nil];
Objective C is very dynamic, so it does not catch this mistake at compile time.
You need to initialize your NSMutableArray by doing
NSMutableArray *selectedOptions = [NSMutableArray alloc] init];
By initializing it with NSArray, you can no longer use the repalceObjectAtIndex:withObject: method and that's the cause of your problem.
After initializing your NSMutableArray with the line above, simply add objects to it with the addObject method.

"unrecognized selector sent to instance" exception error

I've read all the "unrecognized selector sent to instance" answers, but they don't seem to apply to my situation.
I've setting up a NSMutableDictionary like this...
NSMutableDictionary *ObjectDynamic = [NSDictionary dictionaryWithObjectsAndKeys:pObject, #"pFObject",tObject, #"tFObject",nil];
and then at some later point in the code I'm trying to add in another object/key, with this...
[ObjectDynamic setObject:mySprite forKey:#"pSObject"];
But I'm getting an exception on that line, with the...
-[__NSDictionaryI setObject:forKey:]: unrecognized selector sent to instance
Is it not possible to add in another key/value pair like that?
Edit
Simple mistake, I just was trying to make a NSDictionary rather than a NSMutableDictionary! Thanks for the answers anyway.
That's because you initialize an immutable NSDictionary that doesn't have a setObject:forKey: method. Initialize a mutable one instead:
NSMutableDictionary *ObjectDynamic = [NSMutableDictionary
dictionaryWithObjectsAndKeys:pObject, #"pFObject",tObject, #"tFObject",nil];
Since Xcode 4.4 you can also use the new dictionary literals to initialize immutable dictionaries very easily and then use mutableCopy.
NSMutableDictionary *objectDynamic = [#{#"pFObject" : pObject,
#"tFObject" : tObject} mutableCopy];
Note, that in Objective-C you should start variable names with lower case letters.
In order to be able to change the content of a dictionary, you need to make NSMutableDictionary, not an immutable NSDictionary:
NSMutableDictionary *ObjectDynamic = [NSMutableDictionary // <<== Here
dictionaryWithObjectsAndKeys:pObject, #"pFObject",tObject, #"tFObject",nil
];

[__NSCFString superview]: unrecognized selector sent to instance

I am trying to copy a NSMutableArray* into NSArray*, but it does not works and it generates a [__NSCFString superview]: unrecognized selector sent to instance error . Here is the code:
//where gc is a NSDictionary*, recentKey is a NSString*, and _objects is a NSArray*
//gc is an singleton is used to save chache data, with NSKeyedUnarchiver class
//_objects is used to reload the UITableView's data
NSArray *savedNews = [[NSArray alloc] initWithArray:[gc objectForKey:recentkey]];
//this not works...why??
_objects = [[NSArray alloc] initWithArray:savedNews];
Resolution:
Yes, as Herman suggests, the error was external. The savedNews Array was using a class with NSEncoding with an error:
- (void)encodeWithCoder:(NSCoder *)encoder {
//...where element was NSString* and not "UIImageView"
// element should be imgView
if (imgView) [encoder encodeObject:element forKey:#"imgView"];
}
Thanks for all guys.
Somewhere in your App is the superview of an NSString object fetched.
I guess that you assigned an NSString object to something where a UIView is expected.
Could be something like:
someButton.textLabel = someString; // wrong - but should generate a compiler warning
instead of
someButton.textLabel.text = someString; // correct
This is not directly related to your array issue.
First, check what the object in the dictionary is for that key.
NSLog(#"GC Object type for recentkey:%#", [[gc objectForKey:recentkey] class]);
You can only pass an NSArray to initWithArray:
So if that object isn't already an NSArray but you want that object to be IN an array. The do this..
id obj = [gc objectForKey:recentkey]; //Because I have no idea what this is
NSArray *savedNews = [NSArray arrayWithObject:obj];

Why am I getting this: _cfurl: unrecognized selector

My init starts like this:
- (id) init {
[super init];
sounds = makeDictFromArrayOfURLs(getNoiseFileURLs());
[sounds retain];
NSURL *theFirstNoise = [[sounds allKeys] objectAtIndex:0];
CFURLRef uref = (CFURLRef)theFirstNoise;
OSStatus ret = AudioServicesCreateSystemSoundID(uref, &chosenNoise);
When we get to that last line, it throws this:
2011-06-09 23:19:18.744 SuperTimer[94516:207] -[NSPathStore2 _cfurl]: unrecognized selector sent to instance 0x940cfb0
2011-06-09 23:19:18.746 SuperTimer[94516:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSPathStore2 _cfurl]: unrecognized selector sent to instance 0x940cfb0'
Yeah, it's a bit uncompact for debugging.
Just before I get the dump, theFirstNoise contains the expected (sort of) data. (It's description method prints a weird form, but I am informed that's normal.)
Off the top of my head, it looks like theFirstNoise is actually an NSPathStore2 (a private subclass of NSString) instead of an NSURL.
Edit: NSPathStore2 objects will contain file paths. If you need to turn these into NSURLs, you can simply pass them to +[NSURL fileURLWithPath:].
This line:
NSURL *theFirstNoise = [[sounds allKeys] objectAtIndex:0];
is the problem: [sounds allKeys] returns an NSArray of keys, and objectAtIndex: therefore is returning an NSString, and not the URL. I wish the compiler would have been a little more helpful.

NSMutableDictionary with UIButton* as keys - iPhone development

I'm new to iPhone development and I have a question that may have a very simple answer. I am trying to add buttons to a view and these buttons are associated with a custom class that I defined. When I add the buttons to the view, I would like to know what class these buttons correspond to. This is because when I press the button, I need to get some information about the class, but the receiver of the message is another class. I couldn't find information about an error that I'm getting on the web. The problem I have is that I'm trying to create an NSMutableDictionary where the keys are of type UIButton* and the values are of my custom type:
// create button for unit
UIButton* unitButton = [[UIButton alloc] init];
[sourceButtonMap setObject:composite forKey:unitButton];
Of course, the sourceButtonMap is defined in the class and initialized in the init function as sourceButtonMap = [[NSMutableDictionary alloc] init];
The error I get when I try to add the key-value pair is:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[UIButton copyWithZone:]: unrecognized selector sent to instance 0x3931e90'
Is this happening because I can't store UIButton* as keys?
Can anyone point me why I'm getting this error? Thank you all,
aa
One way I found was to use construct an NSValue to use as the key. To create the that use:
[NSValue valueWithNonretainedObject:myButton].
The caveat here seems to be that if the button is garbage collected, the key will hold an invalid reference.
You can get the reference to the UIButton again while looping through the Dictionary like so:
for (NSValue* nsv in myDict) {
UIButton* b = (UIButton*)[nsv nonretainedObjectValue];
...
}
From Apple docs:
The key is copied (using
copyWithZone:; keys must conform to
the NSCopying protocol).
UIButton does not conform to the NSCopying protocol and so you cannot use it as a key in NSDictionary
I've got a cool trick for this.
I cast the pointer to an int (since thats all a pointer really is) and store it in an NSNumber. Using the NSNumber as a key solves this problem and makes sense fundementally because who cares about storing a copy of the button in the dictionary? It makes more sense to me to store a copy of the pointer's info.
If your like me, you'll probably wrap that bit up into a macro as well. Something like this:
#define BOX_AS_NUM(_ptr_) [NSNumber numberWithInt:(int)_ptr_]
Then it's a little cleaner to use in code...
NSDictionary* btnMap = [NSDictionary dictionaryWithObjectsAndKeys:some_obj, BOX_AS_NUM(some_btn), nil];
-(IBAction)someBtnAction:(id)sender
{
SomeObj* obj = [btnMap objectForKey:BOX_AS_NUM(sender)];
[obj doCoolStuffBecuaseIWasJustClicked];
}
UIButtons have a description property that can be used as a dictionary key:
NSMutableDictionary *myDictionary = [[NSMutableDictionary alloc] initWithCapacity:1];
UIButton *myButton = [[UIButton alloc] initWithFrame:CGRectMake(0.0f, 0.0f, 10.0f, 10.0f)];
id myObject;
[myDictionary setObject:myObject forKey:myButton.description];
// somewhere else in code
id myLookedUpObject = [myDictionary objectForKey:myButton.description];
// do something with myLookedUpObject