How do I prevent exception" An instance was deallocated while key value observers were still registered with it." when I don't know the observer? - objective-c

I'm getting the following KVO NSInternalInconsistencyException
> An instance 0x61800005a610 of class portController was deallocated
> while key value observers were still registered with it. Current
> observation info: "<NSKeyValueObservationInfo 0x610000055f90> (
> <NSKeyValueObservance 0x6100000c25a0: Observer: 0x6180000c7460, Key
> path: serialPortManager.availablePorts, Options: <New: NO, Old: NO,
> Prior: NO> Context: 0x0, Property: 0x608000080d20> ")
serialPortManager, by the way, is the singleton [ORSSerialPortManager sharedSerialPortManager]. The obvious answer, of course, is to use
[portController removeObserver:observer forKeyPath:#"serialPortManager.availablePorts"];
Problem is, I don't know who Observer: 0x6180000c7460 is. The key path is set in IB (storyboard) where the content of an NSPopUpButton is bound to a viewController, keyPath self. portController.serialPortManager.availablePorts. portController has a weak reference to serialPortManager.
I have tried looking up the address of the observer in the dSYM via dwarfdump -a in the terminal, but no luck. Is this a new thing? I don't remember having these problems with bindings in the past.
EDIT:
I did not make it explicit, but the address of the NSPopUpButton is not that of the observer.
EDIT 2:
I have implemented #Martin Brugger's solution to Objective C:Object Deallocated while key value observers were still registered with it which is to add symbolic breakpoint for NSKVODeallocateBreak. Unfortunately, the breakpoint is never reached, but error still shows up in the console. I'm starting to think I should file a bug report.

Put the remove observer call into the dealloc method of your class.

Related

Observer not removed when leaving Charts VC with iOS-Charts 2.2.3?

I am working on adding some graphs to my app and had a working version with iOS-Charts 2.1.4. After updating to iOS-Charts 2.2.3 I get the following error when going back from the View Controller containing my CombinedChartView:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'An instance 0x168c5a00 of class Charts.CombinedChartView was deallocated while key value observers were still registered with it. Current observation info: <NSKeyValueObservationInfo 0x171366c0> (
<NSKeyValueObservance 0x15d0dda0: Observer: 0x168c5a00, Key path: bounds, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x15d1b090>
<NSKeyValueObservance 0x15d17a10: Observer: 0x168c5a00, Key path: frame, Options: <New: YES, Old: NO, Prior: NO> Context: 0x0, Property: 0x15db49b0>)'
*** First throw call stack:
(0x217b62eb 0x20f82dff 0x217b6231 0x21f60095 0x20f9d3cd 0x216c9921 0x217774c7 0x216c9bb9 0x216c99ad 0x22943af9 0x259b5fb5 0xf7ed1 0x2137c873)
libc++abi.dylib: terminating with uncaught exception of type NSException
Note: I do not voluntarily register any observers in this VC.
Anybody seeing the same with latest version of iOS-Charts? Great graph library by the way!
Any idea what I could be doing wrong?
I am not sure what's your code problem, but it seems like your library is broken.
iOS-charts did remove the observer in deinit():
deinit
{
self.removeObserver(self, forKeyPath: "bounds")
self.removeObserver(self, forKeyPath: "frame")
}
However your trace is
Charts.CombinedChartView was deallocated while key value observers were still registered with it
It's a paradox. You may want to check your library. when the combined chart is deinited, the observer should be removed. You can also add a break pint in deinit to debug.
I found the solution thanks to #Wingzero's suggestions!
So my issue was that the ChartViewBase.init() method was called twice, thus registering the observers twice but deinit() was only called once so there was a duplicate set of observers left hanging.
The reason for the double init() call is that I started working with the iOS-Charts lib on v.2.1 and at that time needed to manually initialise the CombinedChartView in my VC's viewDidLoad() (or so I thought). With the update to iOS-Charts 2.2.3 (or Swift 2?) this is not needed anymore and will lead to double initialisation and thus one instance of the ChartViews left hanging.
Hope this might help someone else following the same 2.1 -> 2.2.3 update path for iOS-Charts. I've got to say, I highly recommend the iOS-Charts as a graph library for iOS. This was just my error.
Also note that cocoaPod doesn't know about the 2.2 version of the lib yet.

EXC_BAD_ACCESS on animationForKey:

I'm trying to use a recent feature of the Scintilla component, which provides OSX-like text-highlighting effect (the yellow animated bouncing box), and I'm stuck with an error that pops up intermittently :
EXC_BAD_ACCESS
pointing to this particular line :
if (layerFindIndicator!=nil)
if ([layerFindIndicator animationForKey:#"animateFound"])
[layerFindIndicator removeAnimationForKey:#"animateFound"];
(the ifs are mine; just in case I caught the object layerFindIndicator being nil, or deallocated or whatever... Unfortunately, it doesn't help...)
layerFindIndicator is seemingly a subclass of CAGradientLayer. (You may see the full code for layerFindIndicator, here).
Since, I'm an absolute newbie to Quartz Core, could please give me any hint as to HOW this could be debugged?
Since, I'm an absolute newbie to Quartz Core, could please give me any hint as to HOW this could be debugged?
This doesn't have anything to do with QuartzCore specifically (at least, I hope not)—it's general this-object-has-been-killed-before-its-time-how-do-I-find-the-killer stuff.
In Xcode:
Edit your current scheme.
For the Profile action, set it to use the Debug build configuration.
Dismiss that and then hit the Profile command.
Xcode will build for that action and then launch Instruments.
Instruments will prompt you to choose a template; you want the Zombies template. Once you've chosen it, Instruments will create a trace document and run your application. Switch to your application (if it isn't already frontmost), then do whatever causes the crash.
If the crash really is a dead-object crash, Zombies will reveal it. You'll get a flag in Instruments's timeline saying something like “message sent to zombie object 0xd3c2b1a0”, and your program will probably exit shortly thereafter.
In that flag is a tiny little button that looks like this: ➲ except it'll be gray. Click on it.
That takes you to the history of that object (actually of that address, including any previous objects or other allocations that have started at that address). Show your Extended Detail Pane (the one that appears on the right showing a stack trace), then scroll down to the end and then move backward (upward) step by step through time, looking at releases and autoreleases, looking for the one that isn't balancing out the object's allocation or a retain.
The solution will probably involve one or more of:
Changing a property to be strong or weak rather than assign/unsafe_unretained
Adding a property where you previously did not strongly own an object
Rearchitecting some things, if it's not clear which of the above you need to do or if either one of them seems like a filthy hack
Switching to ARC to get weak properties and __weak instance variables (both of which get set to nil automatically when the referenced object dies) and to get local variables being implicitly initialized to nil
But it'll depend on what you find in Instruments. And, of course, there's the chance that your problem—the bad access—isn't a dead object at all and all of the above will not help you.
Try this:
if (layerFindIndicator!=nil){
if ([layerFindIndicator animationForKey:#"animateFound"]){
[layerFindIndicator removeAnimationForKey:#"animateFound"];
}
}
Also check to see if it is released else were.
EDIT:
Another thing I found was you didn't have an white space in the if. Your code should now look like this:
if (layerFindIndicator != nil){
if ([layerFindIndicator animationForKey:#"animateFound"]){
[layerFindIndicator removeAnimationForKey:#"animateFound"];
}
}

Dropbox API in iOS: How to use DBRestClient?

I'm trying to follow the instructions on the Dropbox developer's site, but I can't figure out how to properly add a DBRestClient object. Right now in my .h file after #end I have:
DBRestClient *restClient;
And in my .m file I have:
- (DBRestClient *)restClient {
if (!restClient) {
restClient =
[[DBRestClient alloc] initWithSession:[DBSession sharedSession]];
restClient.delegate = self;
}
return restClient;
}
This is what the Dropbox page tells me to do, I think; however this results in my app crashing (I think because it tries to release restClient when it shouldn't). I've also tried listing restClient as a nonatomic property but then the uploading, etc methods don't seem to work. (The upload method IS working right now, the app just crashes once it's finished uploading...) Help?
Rupesh, the detailed canonical answer based on bee's comment on Apr 20 is that self was getting deallocated.
this means there must have been code that did the following in order.
a variable created by calling the restClient function that returns an object of type (DBRestClient*)
that variable sets it's component (#property? probably) delegate to self in that function (seen in the
question above)
later, the object self was pointing to was deallocated, meaning delegate was not pointing to anything.
later still, there must have been code that was attempting to dereference delegate for some purpose.
do remember that sending messages to nil objc objects only effectively results in nothing happening or a zero assignment if the message being sent is a function. thus a crash must have been due to some other kind of dereference.

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.