Triaging a stack trace

I’ve got an intermittent error in my app - a NilObjectException - that I can’t pinpoint because I am unable to translate the stack trace. I can’t work out which part of my app the error occurs in.

The stack trace looks like this:

In the MyDetailView I have an Event Definition that I’ve called CloseCallback. When I instantiate an instance of MyDetailView, I use AddHandler to assign the instance’s CloseCallBack to a method in the calling view. Then, in the MyDetailView Close event, I execute CloseCallBack which causes my delegated method in the calling view to be called.

Based on the stack trace, it appears as though something is sometimes going wrong in this sequence.

Any suggestions?

Thank you Jean-Paul. I understand that the Close event is called by the view’s destructor but I don’t actually reference anything in the view within my delegated method - I just use it to change a property in the calling view. So the fact that it is called by the destructor shouldn’t matter? And it doesn’t happen every time. In fact, I can’t make it happen at all but every now and then it happens to a user.

If you get sent a stack trace attach it to a bug report for us

Thanks Norman but that’s what I get in the first post. The only thing I did was change the name of the view to “MyDetailView” and leave out all the “Redacted” entries. Everything else is the same. Should I be getting more?

Are you using WeakAddressOf to create the delegate passed to AddHandler?

Yep. And in the callback I am using RemoveHandler to remove it.

Edit: And RemoveHandler in the callback references the view containing the Event Definition. So maybe Jean-Paul is right and the Close event is the wrong place for this? But I wonder why this is intermittent? Many users are doing this many times each day and the error only sometimes happens.

Is it possible the target of the WeakRef is Nil when the event is being triggered?

That was my guess but I don’t see how that could happen. “MyListView” does a PushTo to show “MyDetailView” and sets the callback in “MyListView”. I can’t see how MyListView would be closed before MyDetailView is closed. Maybe, though, it happens if a user double-taps back through the views quickly?

Add some destructors and some logging code to see. Just be aware that it is possible for destructors to fire multiple times (legally).

The problem is that we never get this in-house and none of our small number of TestFlight users ever get it. Only “live” users get it. So it’s a longish process to make these changes and go through App Store Review and then iterate over that.

In some classes I use Delegates for the callback which I pass in to the constructor and I check for nil before invoking them. Is that a better method than using AddHandler with Event Definitions to avoid this? Maybe a refactor is better than a discovery process…

Probably your app has a tabbar
So if you push views then when you click on the tabbar then the stack is resetted to the first view BUT the pushed view are closed and destroyed in creation order, not in reverse order (that is what happens when you pop a view)

So you can call something that doesn’t exist anymore.

I’ve done a quick test and I got the same stack trace.

BTW, this is how iOS works. So it’s not a bug.
You should not save your data (or call “parent” method) on close, but with a button to save the data, or on the fly when you change the data.
The “back” button (and so close) should be used as a cancel button (if you use a save button)

Thank you Antonio. My app does have a tab bar but I can’t make it reset the view stack as you describe. If I tap on one tab, then push a couple of views, then navigate to other tabs, when I return to the original tab the views are still as they were and they seem to pop off the stack in the right order as I tap each view’s back button. Is there a specific way to reproduce this with the tab bar?

I do use buttons to save data - I’ve borrowed from the way Apple uses Edit/Cancel/Done buttons as can be seen in the iOS Contacts app - but on Close I call back into a parent view method to tell the parent view that data has changed and that it needs to refresh or change some state, etc. I can change that to occur on the specific save action (actioned via a button) but there are a number of places where iOS itself saves data as you go back out of a view and not via a button. The Settings app is one example.

You can replicate simply pressing the tab while it is active.

You can save the data on the fly, i.e. when you change/touch/edit save the relative data (this is how settings works)

Ahhh. Taping the same tab, not a different one, causes the issue. I can see it now. Thank you Antonio!

The reason I don’t save data for individual fields is that I need to POST it to our web services and that would be too many small POSTS. But in any case it isn’t saving that causes the issue, it’s calling back to the parent view to tell it to refresh itself. Maybe a delegate that I check for nil before invoking will fix this instead of an Event Definition with an AddHandler.