strange error when reload tableView - ios

I have a very general table view.
when it is refreshed, it will go to fetch list of objects from Parse. Analyze these data in a dispatch_async queue, then refresh table view. Most time, it has no problem, but some time reloadData() crash
Is it crashes because the tableView is reloading data when I call it? (when the tableview is init, reloadData may be called automatically) How to avoid this error? ( there is no error message in console )
EDIT:
I tries to put ?, but does not work

This happens when your tableView (or whatever object you're sending the message to) is nil. So sometime before your async call dispatched this on the main queue, your tableView got dealloacted.
Check this link out for some info:
http://www.touch-code-magazine.com/how-to-debug-exc_bad_access/

You will get EXC_BAD_ACCESS error mostly in the following scenarios:
You are trying to access an object that is not initialized.
You are trying to access an object that no longer exists. Either it’s being released or it’s nil. In ARC mode, make sure you take ownership of the object that you want to use.
You are passing an message to an object that the object doesn’t understand.
It can also happen for bad typecast. Like the lines below where I am trying to access an int with %# in stead of %d.
int myAwesomeInt = 9;
NSLog(#"%#", myAwesomeInt);
How to debug:
Identify what you did that caused the crash. Did it crash while view of a particular view controller didLoad or in a delegate method or on a particular action. That will often help to find the object that is casuing the error.
(In your case look at what specifically happens when you are reloading the table. Do a stack trace line by line and see what your code is doing during a reload)
Most of the time “NSZombies” can help to identify the dead object. You can enable NSZombies by editing your scheme Product -> Edit Scheme -> Diagnostics.
If you still don’t find the root cause then always go backwards from child view controller to parent view controller to see what object needs to be retained or what message needs to be passed properly.
Look into Static Analyzer and Instruments for advanced debugging.
Credit:
The Basic Troubleshooting guide
Hope this helps. Good Luck

Related

What can cause Exc_Bad_Access on first function call in first VC?

Have app in App Store running fine. New version adds a bunch of calculations and minimal new interface. During dev and testing, runs (seemingly) perfectly in Simulator on all devices. Started testing on physical devices, and getting Bad_Access 1 or 2. I read every link on those I could find, and realize it's a difficult error. Using Swift, so no specifically dereferenced pointers of the type mentioned in most links.
Refactored code in many ways over last week. Eventually got it as simple as possible, posted here. My AppDelegate.swift is as basic as possible with no extra stuff or app-specific processing/initialization. The storyboard entry point is a collection view controller of type MainCollectionViewController. In the viewDidLoad method of that controller, the very first statement is a function call to getDrawingInstructions() with parameters. Using default parameter values, and the first two parameters are structs full of CGFloat, Bool, and UIColor.
As you can see, it's crashing as it gets to that func before even entering the func and executing the func's code. The first func call from viewDidLoad of the initial vc.
I've cleaned the build folder and restarted XCode, I'm Swift 5 compliant, I've updated to XCode 11 GM, I've turned on zombies and have no console message. Looking for suggestions on what to try next, 'cause I'm stumped on how I could get screwed up addresses before (seemingly) executing any app-specific code. And remember, this part runs in Simulator and is unchanged from the prior version that ran fine on all devices.
(In different iterations of code, Zombies would yield a console message like objc[7801]: Class _NSZombie_FBSXPCMessage is implemented in both ?? (0x162585890) and ?? (0x162576dd0). One of the two will be used. Which one is undefined. That gives me no clue where to look, especially with the ??.)
Thank you for any insights.
Edit: Per suggestions, removed parameters from function (into struct), but the result was the same as before.
Edit: Removed first argument to the call, a large struct, and got same result. Also got console message: objc[8038]: Class _NSZombie__NSCallStackArray is implemented in both ?? (0x163481590) and ?? (0x163480750). One of the two will be used. Which one is undefined. Not sure how to use this message.
Edit: If the called func is a stub that returns immediately, it is safely processed. So...it's not even entered with a trace if there's code, but it processes if there's an immediate return. Confusing.
Edit: Reconfigured yet again to remove all arguments to the function and just initialize them with default values in the function. That crashes with the same error at the same place, the entry point to the function, without reaching any of the initialization statements in the function. So the first statement in viewDidLoad of the primary VC calls a func with no arguments and crashes with a dereferenced pointer or similar memory error without stepping into that func. I'm not sure how to make that even intentionally happen.

Using UICollectionViewLayoutInvalidationContext to optimize layout calculations during inserts, deletes and moves

I've implemented a custom UICollectionViewLayout for my UICollectionView and also a custom UICollectionViewLayoutInvalidationContext hoping to get good performance.
In my first use case, I have floating headers and during scrolling I only invalidate the headers that need to slide.
I do this as follows:
I return YES from shouldInvalidateLayoutForBoundsChange:.
When my invalidationContextForBoundsChange: method gets called I add stale headers to the context by calling invalidateSupplementaryElementsOfKind:atIndexPaths:.
When invalidateLayoutWithContext: gets called I don't really need to do anything because invalidating the header was enough to get the following key thing to happen: layoutAttributesForSupplementaryViewOfKind:atIndexPath: gets called instead of everything starting over with prepareLayout.
This works great.
My first question is: What about this scenario suppressed the prepareLayout sequence? At first I thought that adding any data to the context (in this case the index paths of stale supplementaries) was enough for Apple to presume I knew what I was doing (iOS8-wise) and not call prepareLayout. I know longer believe that as you'll see below.
My second use case: In practice, my data source almost always adds items only at the end. And for my layout algorithm, that means that the layout of earlier (indexPath-wise) items don't go invalid with new data. I don't want to spend time recomputing potentially large numbers of layout attributes that I don't need to. So I need to do "the right thing" when the client code calls say:
[collection insertItemsAtIndexPaths: newIndices];
by noting what the earliest indexPath in newIndices is and recompute my layout starting from there. Almost always, newIndices starts at the very end and no existing cells go stale--so only attributes for the new cells should be asked of my layout object by Apple.
But note, there is no analogous method to invalidationContextForBoundsChange: for insert/delete/move calls. So I have no way to preconfigure my context with say what indices are coming and going.
So inside the call to insertItemsAtIndexPaths: this is what happens:
My context object gets -init'ed. This happens early--before invalidateLayout is called. At init time, self.invalidateEverything and self.invalidateDataSourceCounts are (NO,NO) (and they're readonly).
Next my invalidateLayoutWithContext: is called now with invalidateDataSourceCounts set to YES--Apple telling me only that my counts are stale. That's useless as that doesn't tell me anything about where to restart my layout calculations. But this is my first (and only chance) to notice something or to do something.
Next my prepareLayout gets called--Grrr! I don't want to start over. I don't want prepareLayout called--or at least I need to stash some info before it's called so I don't overwork. But my only chance was in invalidateLayoutWithContext: and I don't know anything at the time this was called (remember there is nothing similar to invalidationContextForBoundsChange:). Further invalidateDataSourceCounts==YES is useless.
I tried to invalidateItemsAtIndexPaths: any old cell in view inside invalidateLayoutWithContext: to test if that's enough to prevent a call to prepareLayout (in case I did somehow figure out which cells to inval). No go--prepareLayout was still called. So second question: Is invalidateLayoutWithContext: too late to call things like invalidateItemsAtIndexPaths: for Apple to react?
Now to add insult to injury, I notice in the debugger that at invalidateLayoutWithContext: time my context has a private ivar named _updateItems that has all the info I need (at the only time I get a chance to use it). But there is no getter for this ivar. These UICollectionViewUpdateItem entries are delivered only when my prepareForCollectionViewUpdates: method gets called. But guess when this gets called--after prepareLayout and friends (collectionViewContentSize and layoutAttributesForElementsInRect:).
I'm either missing something key or these APIs are broken. Certainly I should be able to add a cell at the end of my layout efficiently. Was I supposed to notice the invalidateDataSourceCounts==YES and just warn my prepareLayout implementation--"Sorry you got called, don't do anything yet. I'll try to call you again later myself after I know what to do."
Or was the client code supposed to somehow create an instance of my context and configure it before calling [collection insertItemsAtIndexPaths: newIndices]? But then how are clients suppose to hand this context down inside the insertItemsAtIndexPaths: call? Further are clients really supposed to be exposed to this implementation detail?

message sent to deallocated instance error

Im constantly being given an error that reads *** -[NSKeyValueObservance retain]: message sent to deallocated instance 0x86c75f10. I have tried running the Zombies template and here is the screenshot of what it provides.
It points to a managedObject, and I'm having trouble figuring out where the object is being deallocated. Here is the block of code that the compiler takes me to after each crash.
- (void)setIsFavourite:(BOOL)isFavourite shouldPostToAnalytics:(BOOL)shouldPostToAnalytics;
{
// check whether we need to generate preferences objects just in time
if(!self.preferences && !self.series.preferences /*&& isFavourite*/)
{
if(self.series)
{
[self.series addPreferencesObject];
}
else
{
[self addPreferencesObject];
}
}
//Crash In here
self.preferences.isFavourite = #(isFavourite);
self.series.preferences.isFavourite = #(isFavourite);
EDIT: If you need to see a larger size of the image here is a larger resolution link.
OK, I hit something similar and found a way to debug this kind of issue with NSKeyValueObservance. To debug, do the following:
In Xcode, open the "Breakpoint Navigator".
Add a new symbolic breakpoint with:
-[NSKeyValueObservance _initWithObserver:property:options:context:originalObservable:]
To that breakpoint, add an action and set it to "Debugger Command".
Set the following command: expr (void)NSLog(#"observer <0x%p>: %# <%p>, property: %#", $arg1, (id)NSStringFromClass((id)[(id)$arg3 class]), $arg3, (id)$arg4)
Click the "Automatically continue after evaluating expression".
Now you can run your application and take the steps necessary to reproduce your crash. And yes, you'll want NSZombies enabled. Note: it's going to run slow and you're going to get a ton of debug output, but just be patient. It'll get there eventually.
When you hit the crash when trying to message a deallocated NSKeyValueObservance, you'll be presented with the address of the original object. Highlight the address and hit cmd-e to enter the text in the search buffer. Then hit cmd-g find the next occurrence of the string in the debugger output. You're going to potentially find the address a couple of times, so look for the address that follows the observer <0x?????> output. The output on that line should tell you what object is being observed and for which property.
In my case, when I figured this all out, it turned out that I was observing a synthesized property that depended on an object in array and during a certain operation, the order of the objects in the array changed without doing the correct KVO notifications, and that caused my crash.
Are you using manual reference counting? If so, why? Convert your app to ARC. Manual reference counting is painful at best, and ARC is much better.
I am an experienced iOS and Mac OS developer and can do either, but I far prefer ARC. It's much less fussy and error-prone.
There is a feature built into Xcode that will convert your project to ARC for you. You might have to do some cleanup afterwords, but it's worth it.
If you do that your problem will likely go away.
As to the specifics, your screenshot is far too small to be able to read it. You will need to post a full-sized image if you want somebody to try to figure out what's going on.
However, in broad terms it sounds to me like you have an autorelease bug.
in manual reference counted code, lots of system method return objects that are "autoreleased." That means that when you receive them their retain count is positive (usually 1) so they stick around. However, they have been added to the "autorelease pool," which means that they are going to be released on the next pass through the event loop if nobody retains them first.
When you receive an autoreleased object you should either accept that it will be released once your current method returns, or retain it.
If you are trying to write Core Data code using manual reference counting and don't understand this then you are setting yourself up for failure.
Core Data is pretty complex, and you should have a solid understanding of Cocoa memory management before attempting to write a program that uses it, especially if you're using manual reference counting.

How to prevent "expression not used" warning with iPad tableView row selection code

I have an iPad app that uses a TabBar setup with a custom SplitViewController and allows selections from a standard left-hand table menu (controlled by a ViewController) to change the contents to the right (landscape only) controlled by a DetailViewController. This runs fine and is in the App Store. I am in the process of updating it to ARC and iOS7 using Xcode 5.1.1 and the conversion has worked and the program seems to run OK in the simulator. However I am getting a warning (which I never had before) in the didSelectRowAtIndexPath method of each of the Views. For example in a class, StylesViewController:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[(StylesDetailViewController *)detailViewController initWithIndexPath:indexPath];
[((StylesDetailViewController *)detailViewController).masterPopover dismissPopoverAnimated:YES];
}
The warning is for the first line (the second is probably not used as the app only supports landscape) and is "expression result unused". The line is necessary, the program does not crash, so I assume that this warning could be ignored. However, knowing Apple, I would prefer not to submit an app with warnings for review. Can anyone suggest a harmless statment to 'use' the 'result of the expression' and hence silence the compiler?
Sending a message with the string 'init' in it's selector to an object that is not created on the same line of code is an important anti-pattern in iOS/Objective-C. The details are not entirely necessary, but the important (and relevant) bit of info is that technically an 'init' method returns an id, which is actually allowed to be a different object than the one that the message was sent to!
Your warning is simply telling you that you are not using that object. The calling of an init method outside of it's alloc line may have other unwieldy implications.
One caveat to this answer: The specifics will certainly depend on your implementations of the method in question, and posting that method (at least it's signature) will help. However, even if you are using that method to simply prime the object in a way that can/should happen over and over and apart from the alloc step, I highly encourage you to avoid the use of the string init in the name... I like to use loadWith... or something similar.

Debugging strategies for over-retain in ARC?

I've got some objects that are passed to a lot of different views and controllers in my application. They're not getting deallocated when I expect them to. Obviously there is an errant strong pointer somewhere, but the surface area of where it could be is very large--these objects are moved into and out of a lot of different data structures.
My usual go-to solution here is Leaks (which reports no cycles) and Allocations (which lists 500+ retain/releases for this object). Is there any way to reduce my search space here?
Ideally there would be a tool that would let me type in a pointer and see all the strong references to the object, and I could probably eyeball the list and find the extra reference in about 60 seconds. In fact, there is such a tool -- the Object Graph instrument -- but it's not available for iOS software.
You want the Allocations instrument. To track an individual object type, start the application. You need to create a heapshot at every significant event (I usually create them at points when you've just transitioned to or from a view controller).
Once you've got a heapshot that should have the object you're interested in tracking down, then you should be able to find that object type under the heapshot's disclosure triangle. For each object of that type, you can get a history of what retains and releases have been sent to that object by clicking on the arrow in that object's row.
The simplest method to identify whether there is retain cycle or not by just putting a breakpoint in your controller's dealloc()/deinit()(swift) method and whenever you pop your controller check this methods getting called or not if there is retain cycle present in your controller this methods won't get called.
Swift
deinit {
print("Memory to be released soon")
}
Objective C
- (void)dealloc {
NSlog("Memory to be released soon");
}
If you want to get more details about the strong references and root causes you should go with Instrument as the other answer.

Resources