How XCode knows about name of function at compile time? - ios

I have written simple code to practice selector in Objective C, which is working fine
NSMutableArray *array = [NSMutableArray arrayWithObjects:#"A",#"B", nil];
NSLog(#"Before adding %#",array);
SEL message = #selector(addObject:); //I will change this line
if([array respondsToSelector:message])
{
[array performSelector:message withObject:#"C"];
}
NSLog(#"After adding %#",array);
But as soon as I change selector line to,
SEL message = #selector(addobject:);// Just changed name of selector
XCode starts giving warning :
Undeclared selector 'addobject:'
Now, question is how XCode knows at compile time about name of method is correct or not. Is there always list of selector generates internally for whatever object I am creating? In this case for NSMutableArray

All Xcode knows is that there is no class, either in the system code or in your program, that declares a selector called addobject. You can prove this by creating a custom class that declares an addobject method, and the warning should go away, but of course the program will crash with a unrecognized selector sent to object error message.

Related

Error when adding NSString object to my NSMutableArray

I am getting this error when trying to add the NSString object named object to my array :
erminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7fc48ae52ba0'
Not sure why this is so. I was originally using NSArray to changed it to NSMutableArray but I am still having problems with it. Code is below:
-(NSMutableArray *)getReplyArrayForMessage: (NSString *)message {
//get the array
NSMutableArray *replies = [self.messageDictionary objectForKey:message];
NSLog(#"%#",replies);
//if no replies we init the base set
if([replies count]==0) {
//get the base array
//this also works if a key just isn't in the dictonary
return replies=[self getBaseArray];
}
else {
//add the other message
NSString *object = #"Send a different message";
[replies addObject:object];
return replies;
}
}
If anyone could give me a pointer to why this is happening I would appreciate it. Noob here.
The array is immutable (NSArray), not mutable (NSMutableArray). You can create a mutable array from an immutable array using mutableCopy:
NSMutableArray *replies = [[self.messageDictionary objectForKey:message] mutableCopy];
I know this from the exception text:
-[__NSArrayI addObject:]: unrecognized selector sent to instance ...
^^^^^^^^^^
EDIT I've missed off some important information from my original answer.
Having used mutableCopy you now have a copy of the array and the original array (from self.messageDictionary objectForKey:message) will remain unchanged after you add your element. This is almost certainly not what you intended.
As I've mentioned in the comments below, you probably want to create a custom object to hold these details (or an array of custom objects) that should be created from the message dictionary as soon as you receive it. The effort required to create a custom object will pay for itself tenfold in the long term.
You are trying to add an NSString to an NSArray (which looks like an NSMutableArray) since you initialized it as one. This means that the object that you store in your messageDictionary is actually of type NSArray, and not NSMutabelArray. So, assigning it to an object of type NSMutableArray won't actually change its type and make it mutable.
It's an easy fix:
NSMutableArray *replies = [[NSMutableArray alloc] initWithArray:(NSArray *) [self.messageDictionary objectForKey:message]];
Or you can go with mutableCopy (as suggested by #trojanfoe) which is a shortcut but will lead to the same result.
I can tell because the error message says -[__NSArrayI addObject:]: unrecognized selector sent to instance 0x7fc48ae52ba0'. Notice the I at the end of __NSArrayI, this means that this array is actually immutable, so you can't add objects to it.

Accessing an instance throws exception - NSDictionary NSArray

I am a beginner in Objective-C and do struggle a bit with dictionaries and arrays.
My goal is to create a table view where every cell contains a picture from a server. The url for the pic comes from a JSON call. I downloaded the example from Apple called "lazy table view" and tried to merge it with the one I found inside a Standford iOS Class. So far everything works, besides the picture. Xcode throws the following exception, once I try to access the icon:
-[__NSCFDictionary Icon]: unrecognized selector sent to instance 0x10b845ff0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFDictionary Icon]: unrecognized selector sent to instance 0x10b845ff0'
The code in question looks like this:
#interface FlickrPhotosTVC : UITableViewController
#property (nonatomic, strong) NSArray *photos;
#end
#interface ClRecord : NSObject
#property (nonatomic, strong) UIImage *Icon;
#define FLICKR_PHOTO_TITLE #"title"
ClRecord *clRecord = self.photos[indexPath.row];
cell.textLabel.text = [clRecord valueForKeyPath:FLICKR_PHOTO_TITLE]; // works
if (clRecord.Icon) NSLog(#"test"); // throws exeption
Somehow this seems to be releated with the types. Trying to access an array, while accesing a dictionory or similar. I found some releated posts on stack, but could not solve it so far.
Thank you for any help!
The objects stored in self.photos seems to be dictionaries objects and not ClRecord objects. The error you get say that you are calling Icon method on a dictionary object.
Check where you fill your photos array to make sure you put ClRecord objects in it and not dictionaries objects.
You could do NSLog(#"My photos array is ---%#",self.photos);
This will give you what exactly you have in your array.
Case 1: If you have a dictionary objects then :- You should do NSDictionary *dict = self.photos[indexPath.row]; ClRecord *clRecord = [dict objectForKey:#"YourKeyForImage"];
Case2: If you have images as you expect, then make sure you import ClRecord header file, you have non nil object at your specified [indexPath.row] index and other necessary initializations.
Hope this helps. Link1

removeAllObjects crashes app

I want to clear my array, what i did is,
I have tableview view in my app, first i am fetching data from server and loading it in tableView.
-(void)viewDidLoad{
//fetching data from server using background thread and storing it in array called (msg_array)
[table reloadData];
}
when last row comes on screen i want to fetch new data from server and i want to display it,
-(void)LoadMoreData{ //this method gets fire when last cell is on screen
if ([msg_array count]>0)
{
[msg_array removeAllObjects]; //crashes here
}
}
This gives the error:
Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[__NSArrayI removeAllObjects]: unrecognized selector sent to instance
Why does it cause a crash:
The array is allocated like this:
msg_array = [dictShow copy];
dictshow contains the data and copying it to msg_array and dictshow is mutabledictionary
(Taken from comments)
'-[__NSArrayI removeAllObjects]: unrecognized selector sent to instance
This means that the array doens't have the method you're trying to call. That's because it is an immutable array (NSArray), not mutable (NSMutableArray).
Either make it mutable if you want to mutate it. Or, replace:
[msg_array removeAllObjects];
with:
msg_array = #[];
Based on your comment, the array should be mutable. That means that you have a mutable property / instance variable, but that you're creating an immutable instance to store into it. Find that location and update it (to create / return a mutableCopy at least).
Its because you are trying to modify a immutable array, you have two options here:
msg_array = #[];
OR
NSMutableArray *mutableMessageArray = [msg_array mutableCopy];
[mutableMessageArray removeAllObjects];
msg_array = [mutableMessageArray copy];
I prefer the first option as its neater, but if you need to do any other modifications of the array the latter option might be best for you.
NB:
Check how you declare msg_array, can you post that code?
msg_array could be immutable thats why it is crashing. removeAllObjects is only for NSMutableArray
__NSArrayI, looking carefully at this bit, we can see it's suffixed with an i. This i means the array is immutable and can't be changed.
You possibly want to use an NSMutableArray
msg_array = [dictShow copy]; dictshow contains the data and copying it to msg_array and dictshow is mutabledictionary
This is very strange! I expect that calling copy on a dictionary would always return a dictionary. Unless you are mistaken there, I can only imagine that either the dictionary's keys or its values are being returned.
I think you might have meant mutable array; assuming you did, the call to copy returns an immutable object, try [dictShow mutableCopy] instead
msg_array = [NSMutableArray arrayWithArray:_MoodsArray].mutableCopy;

unrecognized selector "length" when attempting to log entire managed object with overridden getter/setter

I use core data to store some arrays as strings. The strings are prefixed with STRINGFROMARRAY and delimited by &,&.
I thought it would be neat to override the setters and getters so I wouldn't have to provide code to convert them every time I needed access. I have created a managed object subclass called TestEntity with only one attribute, "memberIds" (string). I have verified that my custom setter and getter seem to work fine:
TestEntity.h:
#interface TestEntity (CoreDataGeneratedAccessors)
- (NSArray*)memberIds;
- (void)setMemberIds:(NSArray *)memberIds;
#end
TestEntity.m:
#implementation TestEntity
#dynamic memberIds;
- (NSArray *)memberIds
{
[self willAccessValueForKey:#"memberIds"];
NSArray *memberIdsArray = [NSArray arrayWithArray:[[[self primitiveValueForKey:#"memberIds"] substringFromIndex:15] componentsSeparatedByString:#"&,&"]];
[self didAccessValueForKey:#"memberIds"];
return memberIdsArray;
}
- (void)setMemberIds:(NSArray *)memberIds
{
NSString *stringFromArray = [#"STRINGFROMARRAY" stringByAppendingString:[memberIds componentsJoinedByString:#"&,&"]];
[self willChangeValueForKey:#"memberIds"];
[self setPrimitiveValue:stringFromArray forKey:#"memberIds"];
[self didChangeValueForKey:#"memberIds"];
}
#end
I can set an array value and it properly stores as a string. I can also use valueForKey to log the value after it's set, and it properly prints as an array.
However, when I attempt to log the entire managed object (without valueForKey:), I get a [NSArray length] unrecognized selector error.
Here's the code I'm using to test this:
NSManagedObject *test = [NSEntityDescription insertNewObjectForEntityForName:#"TestEntity" inManagedObjectContext:[SyncEngine sharedEngine].managedObjectContext];
[test setValue:[NSArray arrayWithObjects:#"1", #"2", #"3", nil] forKey:#"memberIds"];
NSLog(#"%#", [test valueForKey:#"memberIds"]);
NSLog(#"%#", test);
And here's the output:
2013-08-24 13:59:27.820 0.1[1440:19d03] (
1,
2,
3
)
2013-08-24 13:59:27.820 0.1[1440:19d03] -[__NSArrayI length]: unrecognized selector sent to instance 0xa533800
Why is the length message getting sent to my array? And how can I prevent this crash? Thanks!
I think the problem is that you have overriden memberIds methods.
In your model, memberIds should return a string, and you've overriden it to return an NSArray.
So, when your managedobjet is trying to generate its description, it is assuming that memberIds is a string.
I think the best way to do that it to name your custom getter / setter differently than your model attribute.

issue with a selector

I'm running into problems with a selector. I'm trying to dynamically name an array, winnerArray1, winnerArray2, winnerArray3, etc.
The variable someVariable is in a loop that increases so that will get incremented.
I get unrecognized selector sent to instance
int someVariable = 1;
NSArray *winnerArray;
NSString *tempLoopString;
while(someVariable < 4){
tempLoopString = [NSString stringWithFormat:#"winnerArray%d", someVariable];
SEL selector = NSSelectorFromString(tempLoopString);
winnerArray = [self performSelector:selector];
if ([winnerArray do_stuff]) {
do stuff here
}
someVariable++
}
You can't refer to a variable by name like that.
You should look into using key value coding. With that, you can interrogate a property of some object using the method valueForKey:

Resources