How to understand which unrecognized selector sent to instance - selector

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.

Related

Objective-C parsing JSON NSNULL error, location not shown

I am parsing quite a large JSON model, and I have a LOT of objects set up to handle all the data. I recently added more data to the JSON model, to test it out, and I am getting this error
-[NSNull count]: unrecognized selector sent to instance 0xaed678
However, I need to know EXACTLY which function is crashing in order to fix it, but for some reason, xCode does not tell you where the function crashes which seems very odd, as that is very important information if you want to rectify the bug. Is there anyway for me to find out exactly which method or function caused the application to crash?
Thanks in advance
Set a breakpoint on unrecognized selector:
Creating breakpoint in Xcode for unrecognized selector
Then trace back in the code.

How to find out the location of unrecognized selector exception in Objective-C?

How do I go about finding out where in my code caused the following exception?
2012-08-15 09:24:27.414 TestProject[82870:17303] -[TestObj doIt]: unrecognized selector sent to instance 0x1106f320
Best way to do it: Add a breakpoint to capture all exceptions, that will give you the line of code where you are getting the exception. From the console, you will get the same message you are posting on your question, so, use the pointer address to print the object that is getting the exception. If the object is garbage(the debugger wont print it), that means you are overreleasing an object. If you have zombies enabled, you will find a prefix NSZombie__ on your class name. That also means overrelease. If you get a different class than the one you are expecting, you are switching the objects at some point and sending a message to the wrong object.
Go to the breakpoints navigator (on the left)
at the bottom you have a +,
add an exception breakpoint on all exceptions
set a breakpoint for thrown exceptions. by default, it will pause when an exception is thrown -- there you will see the backtrace and values.
if it's completely random (e.g. not reproducible), then you may have best luck running Instruments with zombies enabled.

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.

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

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

Objective-C respondsToSelector

From what I have learned so far: In Objective-C you can send any message to any object. If the object does implement the right method it will be executed otherwise nothing will happen. This is because before the message is sent Objective-C will perform respondsToSelector.
I hope I am right so far.
I did a little program for testing where an action is invoked every time a slider is moved. Also for testing I set the sender to NSButton but in fact it is an NSSlider. Now I asked the object if it will respond to setAlternateTitle. While a NSButton will do and NSSlider will not. If I run the code and do respondsToSelector myself it will tell me the object will not respond to that selector. If I test something else like intValue, it will respond. So my code is fine so far.
- (IBAction)sliderDidMove:(id)sender
{
NSButton *slider = sender;
BOOL responds =
[slider respondsToSelector:#selector(setAlternateTitle)];
if(responds == YES)
{
NSLog(#"YES");
}
else
{
NSLog(#"NO");
}
[slider setAlternateTitle:#"Hello World"];
}
But when I actually send the setAlternateTitle message the program will crash and I am not exactly sure why. Shouldn't it do a respondsToSelector before sending the message?
First of all, the name of a method (its selector) includes all subparts and colon characters, as mvds said.
Second of all, the method -respondsToSelector: is not called by the runtime, it's usually called by the user (yourself or APIs that want to know if a delegate, for example, responds to an optional method of the protocol).
When you send a message to an object, the runtime will look for the implementation of the method in the class of the object (through the object's isa pointer). It's equivalent to sending -respondsToSelector: although the message itself is not dispatched. If the implementation of the method is found in the class or in its superclasses, it's called with all the arguments you passed in.
If not, then the runtime gives the message a second chance to be executed. It will start by sending the message + (BOOL)resolveInstanceMethod:(SEL)name to the class of the object: this method allows you to add the method at runtime to the class: if this message returns YES, it means it can redispatch the message.
If not it gives the message a third chance to be executed, it sends - (id)forwardingTargetForSelector:(SEL)aSelector with the selector, this method can return another object that may be able to respond to the selector on behalf of the actual receiver, if the returned object can respond, the method is executed and the value is returned as if it was returned by the original message. (Note: This is available beginning with OS X 10.6 or iOS 4.)
If the returned object is nil or self (to avoid infinite loops), the runtime gives the message a fourth chance to execute the method… It sends the message - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector to get a method signature in order to build an invocation. If one is provided then an invocation is sent through the message - (void)forwardInvocation:(NSInvocation *)anInvocation. In this method you can parse the invocation and build other messages to send to other targets in any ways you want, and then you can set the return value of the invocation… That value will act as the return value of the original message.
Finally, if no method signature is returned by the object, then the runtime sends the message - (void)doesNotRecognizeSelector:(SEL)aSelector to your object, the implementation of this method in NSObject class throws an exception.
For one thing, the selector is not only the "name" of the message, but also what follows, i.e. the arguments, and their names.
So the correct selector for some -(void)setAlternateTitle:(NSString*)str would be
#selector(setAlternateTitle:)
with the :
As for your problem: If a class respondsToSelector() and you perform that selector, you shouldn't get a crash on sending an unknown selector. What kind of crash log do you see in the debugging window?
(ps. why not include the [slider setAlternateTitle:...] in the if ( responds ) { ... } conditional block?)
"This is because before the message is
sent Objective-C will perform
respondsToSelector."
I guess this is not correct. If the object does not respond to selector, it will crash at runtime. There is no automatic checking by the system. If there was a check by the run time system then we should never get "unrecognized selector sent to instance" exception.
Please make me correct if I am wrong.
EDIT: This is not a straight forward crash, but the default result is the process will be terminated. The whole sequence is already explained in comment and other answer, so I am not going to write that again.
There is an +instancesRespondToSelector: method. As the name suggests, it tells you whether the instances of the class implement that method.