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

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.

Related

iOS9 storyboard what is unhandled action (handleNonLaunchSpecificActions)?

I've noticed the following error popping up in the console when running my app on iOS 9 when using a storyboard. I'm using xCode7. Is this something I need to be concerned about?
-[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion:] ** unhandled action -> <FBSSceneSnapshotAction: 0x176bfb20> {
handler = remote;
info = <BSSettings: 0x176a5d90> {
(1) = 5;
};
}
There is nothing wrong with your code. This is a logging message internal to Apple, and you should file a radar about it.
There are two hints that show that this is probably Apple's code:
The underscore leading the method name _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion is a convention indicating that the method is private/internal to the class that it's declared in. (See this comment.)
It's reasonable to guess that the two letter prefix in FBSSceneSnapshotAction is shorthand for FrontBoard, which according to Rene Ritchie in "iOS 9 wish-list: Guest Mode" is part of the whole family of software related to launching apps:
With iOS 8, Apple refactored its system manager, SpringBoard, into several smaller, more focused components. In addition to BackBoard, which was already spun off to handle background tasks, they added Frontboard for foreground tasks. They also added PreBoard to handle the Lock screen under secure, encrypted conditions. [...]
I have no idea what the BS prefix in BSSettings is for, but
BS is shorthand for BackBoard Settings, and an analysis of this log message would indicate that it's not anything you did, and you should file a radar with steps to reproduce the logging message.
If you want to try and grab a stack trace, you can implement the category linked to here. Some would argue that overriding private API is a bad idea, but in this case a temporary injection to grab a stack trace can't be too harmful.
EDIT:
But, we still want to know what this action is. So I put a breakpoint on -[UIApplication _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion] and started printing out register values and found a class called FBSceneImpl which had a whole bunch of information about my application:
We are able to find out which private method is called next (stored in the program counter, instruction pointer, register 15.)
I tried finding the un-handled FBSceneSnapshotAction referenced in the log, but no dice. Then, I subclassed UIApplication, and overrode _handleNonLaunchSpecificActions:forScene:withTransitionContext:completion. Now I was able to get at the action directly, but still, we don't know what it is.
Then, I looked at the FBSceneSnapshotAction again. Turns out it has a superclass called BSAction.
Then I wrote a tool similar to RuntimeBrowser and looked up all of the subclasses of BSAction. It turns out that there's quite a list of them:
The two method names we have (one from the log and one from the program counter on the devices) indicate that these actions are used under the hood for passing actions around the system.
Some actions are probably sent up to the app delegate's callbacks, while others are handled internally.
What's happening here is that there is an action that wasn't handled correctly and the system is noting it. We weren't supposed to see it, apparently.
AFAIK, the info above is related to iOS during snapshot the screen (i suppose for double click home multitask related behaviour).I deeply investigated my application and seems that it does not get any side behaviours. You can safely ignore it, for now.
You can use the following gist simple category to test yourself against the calls to the above function:
I have figured it out, it will happen when you have IBAction method declared in .h or .m file but you have not bind it to any control.
.m example:
- (IBAction)click:(id)sender{
}
but not assigned this method to any control in storyboard.
haven't find out why it happens in my app, but at least you can catch the exception, if you want to keep this from popping up in your log pane. It's not a solution, but it might give you more insight why it is happing by inspecting any of the arguments that are passed in the catch.
swift 2 version:
import UIKit
extension UIApplication {
func _handleNonLaunchSpecificActions(arg1: AnyObject, forScene arg2: AnyObject, withTransitionContext arg3: AnyObject, completion completionHandler: () -> Void) {
//whatever you want to do in this catch
print("handleNonLaunchSpecificActions catched")
}
}

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?

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.

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"];
}
}

Why does this Objective C call appear to hang?

A friend of mine discovered some strange behaviour with NSDictionary, and I'm curious as to why it happens. Consider the following code:
NSDictionary *dict = [[NSDictionary alloc] init];
// Oops, we can't mutate an NSDictionary
[dict setObject:[[NSNull alloc] init] forKey:#"test"];
NSLog(#"Set");
The code produces a warning upon compilation that "'NSDictionary' may not respond to 'setObject:forKey:'". That's all well and good, and if you run it anyway, you'll get this output in the console:
-[__NSCFDictionary setObject:forKey:]: mutating method sent to immutable object
Again, exactly what you'd expect to happen. However, at this point the app does not crash or terminate due to an uncaught exception. The setObject:forKey: method simply never returns, and the app appears to hang; the following NSLog is never executed. If you try to step over or into the method using GDB, debugging just seems to end, but without any explicit error message. The app continues to run, but the debugger provides no clue as to where in the code the execution is "stuck."
What's going on here? What is the app actually doing in this case, and why doesn't it crash with an NSInternalInconsistencyException or something of the like?
Edit: For those who have asked, I'm running XCode 4.1 on OS X Lion (10.7.2), building with "Apple LLVM compiler 2.1." I'm using all of the default settings you get with a new Cocoa project in XCode 4. I experience the same non-crashing behaviour regardless of whether I debug the program or just "Run" it. Changing from Debug building to Release building makes no difference. I can even locate the .app file manually in Finder and double click on it to execute it outside of XCode, and it still does not crash.
Exceptions do not crash AppKit programs. NSApplication installs a default exception handler that catches exceptions that your code doesn't. Then you just go back into the runloop as normal.
Lots of apps exhibit this behaviour. It's a common cause of inexplicable blank views/windows. If an exception happens before a view manages to finish drawing, the view will be blank, but the app won't crash. Exceptions only cause a crash if you deliberately change the default exception handler to crash.

xCode says the object might not respond to selector while I'm checking for it

I have the following code:
if([node respondsToSelector:#selector(setOpacity:)])
[node setOpacity:127];
I know node might not respond to setOpacity: so I check for it, but xCode still warns against it. is there any way of safely calling the selector without xCode complaining? the warning is:
/path/file.mm:79: warning: 'CCNode' may not respond to '-setOpacity:'
if([someIndexes respondsToSelector:#selector(setOpacity:)])
[(id)someIndexes setOpacity:127];