What does the “unrecognized selector sent to instance” error mean? - objective-c

I am getting a crash in my app due to the following error:
-[NSCFString count]: unrecognized selector sent to instance 0x612b060
Can anybody tell me what does it mean and how can i find the line in my code with reference 0x612b060

You are calling count method on an object (probably a collection e.g array, dictionary, or set) which is released or has not been initialized yet.

You are sending message "count" on NSCFString, means, calling "count" method on NSString datatype.
To find the code, you can use Stack trace, but I am sure what you are doing is:
Assign NSString data on NSArray or (Array datatype) and trying to count.

Most likely this happens because you have a collection object (eg NSArray, NSDictionary) that you do not retain properly.
Try to use NSZombies to find the object that got released.
Right-Click on the executable in the Executables group in Xcode. Select Get Info
Select Arguments tab.
In Variables to be set in the environment create a variable called NSZombieEnabled and set its value to YES. Don't forget to activate it.
Turn on breakpoints and run your code.
the debugger will point you to the object that gets released to early.
After you've done debugging this problem you should deactivate NSZombies. NSZombies won't release any memory, it just marks the objects as released.
So you will end up in a memory warning sooner or later.
You can simply remove the checkmark in front of it to deactivate NSZombies.

Did you mean to call length on your string?

Maybe someone will need this:
When I had this kind of problem I used:
[ myarray retain];
after
myarray = [NSArray arrayWithObjects: ...];
and it worked. I think it was because my array destroying itself too early.
But I don' t know how I can now release this object?
Just [myarray autorelease]? Is there something opposite to retain ?

A practical example:
Sometimes, there is a practical difference which I don't understand clearly yet. valueForKey didn't work in SOGo-3.1.4's code trying to call an unavailable "method" ASProtocolVersion on the context object:
`EXCEPTION: <NSException: 0x55f43f93e4d0> NAME:NSInvalidArgumentException REASON:-[WOContext ASProtocolVersion]: unrecognized selector sent to instance
whereas objectForKey works (and is the usual way to query the context object elesewhere in the code).
See https://github.com/inverse-inc/sogo/pull/217/files

Related

How to understand which unrecognized selector sent to instance

How do i figure out which selector is this , from this error message ?
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayM length]: unrecognized selector sent to instance 0x178059b30'
how do I make xcode give me normal error messages, ones that will tell me where the problem is exactly?
That is a normal error message. The system can't tell you more than this.
But with the help of the debugger (exception breakpoints enabled), and a good understanding of Objective-C you should be able to diagnose the problem.
Here is what we know from the exception message:
The unrecognized selector was length. The most common class that has this method is NSString.
The object that received this method was a NSArray
After the exception breakpoint was triggered type po 0x178059b30 into the debugger to inspect the array. This content of the array can give you hints to figure out how the problem was caused initially.
From the debugger position in your code you can see what triggered the bug.
You say your code failed at [_label setText:name].
This method expects a NSString, during assignment a couple of NSString specific methods are called, length is one of these methods. Which confirms point one of our guess.
There are two possibilities:
name is actually a NSArray because you wrote code that assigned the wrong object. This often happens if you don't check the results you get from a dictionary or an array.
You have a memory problem and name was deallocated prematurely and an array is now where the NSString should be.
To rule out the second option a run of the Analyzer is often enough. It will point out most memory problems.
Another way to decide which of the two is more likely you use the output of po 0x178059b30. If the array holds objects that are related to the expected value of name (e.g. it actually contains name) there is a high chance that you did assign the wrong object. In this case look where you set name, and put a check around it.
If you use a property you can use something like this to figure out where you assign the wrong object:
- (void)setName:(NSString *)name
_name = [name copy];
if (![name isKindOfClass:[NSString class]]) {
NSAssert(NO, #"Wrong class %#", name);
}
}
A breakpoint will be triggered when the assigned object is not a NSString instance, and you can inspect the call stack to see where you did something wrong.
Make sure to remove that code after you are done debugging. You MUST NOT use such checks to prevent bugs in your code.

Crash while Attempting to set Non Property List Objects in NSUserDefault

I tried to set a NSString object as below:
[[NSUserDefaults standardUserDefaults] setObject:[[self formModel] attributeAsString:#"someKey"] forKey:#"someValueKey"];
It doesn't crash every time.
At some point it crashes saying "Attempt to set a non-property-list object as an NSUserDefaults value"
Can anybody help me to set this value properly and get it whenever requires?
Thanks in Advance.
If you want to store object other then NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary, you should archive it to create an instance of NSData.
You can use propertyList:isValidForFormat: method of NSPropertyListSerialization class to validate property list
Are you sure that actually returns an NSString (or subclass of NSString), and not, say, an NSAttributedString?
Are you sure it's that line? Try adding a breakpoint on 'abort', and then waiting for it to be hit. You should be able to look up the stack and see where in your code you're triggering the issue, and then inspect the value you're passing into NSUserDefaults.
Basically, it's very unlikely that you're actually passing a valid string in, there's likely a bug in your code that's causing something else to be there.
(Edit to add the idea I had in a comment)
Oh, one other idea: You can use the function CFPropertyListIsValid to determine if an object is a valid property list object. That could let you catch it earlier, in your code, and see what's going on.

ARC causes a dangling pointer

Ok I use arc in my main application but have ported a control which does not use arc .. every thing compiles etc but I get EXC_BAD_ACCESS error on the controls event ...
The event is initiated from Delegate Method
Is there a way to get the pointers text value from the hex code value i.e Name* from the 0X00AA0 address ?
And what is the standard way of checking what arc is deallocating?
Is there a way to get the pointers text value from the hex code value i.e Name* from the 0X00AA0 address ?
Try to play around with llvm debugger. After something crashes or at your breakpoint use something like this:
expression 0x00aa0

NSArray: Why is SIGABRT sent instead of an 'index out of bounds' kind of error?

Ok. So I had this extremely weird SIGABRT error on a complex Objective-C iOS program that I'm working on, and after one day of tracking I found the culprit.
Let's say we have the following code:
NSArray *a = [NSArray arrayWithObjects:#"a", #"b", #"c", nil];
NSLog(#"tada: %#", [a objectAtIndex:-1]);
Why the hell will this terminate the program with Program received signal: SIGABRT and the debugger not even pointing to my code (but rather in some assembly part) instead of a nicer 'index out of bounds' and 'hey, this line of code here be wrong' error?
I thought I messed up the project config, so I reproduced this on a brand new project: same result.
Is there a way to configure XCode to be more nice and indicate this kind of errors in a more human understandable way ?
As the documentation says:
If index is beyond the end of the array (that is, if index is greater
than or equal to the value returned by count), an NSRangeException is
raised
And the default action, when no exception handler is defined, is to... well... you can see what the default behaviour is.
You can use #try/#catch to trap the exception, but that's not really Objective-C-ish. You know how many elements are in the array; there's no real need for you to be accessing elements that don't exist.
Exceptions like this normally have a stack trace, so you can go back to the line of code causing the error. (It might be worth switching between LLDB and GDB if it's not working correctly. LLDB is faster and smaller but not completely reliable.(
You should see something along the lines of "index of out range" if you look in the console log in Xcode. SIGABRT is the result of an assertion being fired. Sometimes you have to hit "Continue" after the crash in order to get the message to print.
The debugger tells you where the crash actually happened. It doesn't know what the original cause was. If the debugger leaves you looking at the assembler, just move up the stack until you reach your code.

Why is perform:withObject method not found?

I want to fix warnings in my application code. I have an AddressBookModel.h which implements the TTModel protocol.
You find both interface and implementation of the AdressBookModel in the answer of this question. This is exactly how I implemented it How to use Three20 TTMessageController?
However for
[_delegates perform:#selector(modelDidStartLoad:) withObject:self];
and some other similar selectors I get warnings like
Method -perform:withObject not found (return type defaults to id)
Since _delegates is an array
- (NSMutableArray*)delegates {
if (!_delegates) {
_delegates = TTCreateNonRetainingArray();
}
return _delegates;
}
some suggested to use makeObjectsPerformSelector but this gives me an unrecognized selector sent to instance exception.
Here is the TTModel source code: http://api.three20.info/protocol_t_t_model-p.php
Why is perform:withObject missing? Is performSelector:withObject an alternative (my app crashes using it)?
_delegates is an array of delegates. It is not a true delegate, as signified from the name which is in plural form. An array does not respond to the -modelDidFinishLoad: method — its elements do.
You need to take each element out of the array and call the method of them, e.g.
for (id<TTModelDelegate> delegate in _delegates)
[delegate modelDidFinishLoad:self];
or even easier, using NSArray's -makeObjectsPerformSelector:…:
[_delegates makeObjectsPerformSelector:#selector(modelDidFinishLoad:)
withObject:self];
perform:withObject: method that produces this warning is defined in NSArray(TTCategory) category in NSArrayAdditions.h file in Three20 framework. You need to ensure that this header is imported/referenced properly by compiler, i.e. you need to look at importing this specific header or check your Three20 integration configuration.
You do not need to change this method to makeObjectsPerformSelector: since this is just an import problem (your code runs fine but just produces compile warnings).
Reading between the lines, it looks like you want the objects that are in your _delegates array to all perform a particular selector. You need to call -makeObjectsPerformSelector:withObject: like this:
[_delegates makeObjectsPerformSelector: #selector(modelDidCancelLoad:) withObject: self];
You are mistyping modelDidCancleLoad: should be modelDidCancelLoad:
'NSInvalidArgumentException', reason:
'-[__NSCFArray modelDidCancleLoad:]: unrecognized selector
sent to instance 0x24f480'
Make sure your _delegates is what you are expecting it to be. It seems to be an NSArray.