Is -scrollViewDidScroll: called on a background thread? - ios

I'm experiencing something odd with -scrollViewDidScroll:
In every call I obtain the last object from an NSMutableArray, and add another object to that NSMutableArray.
But it seems the NSMutableArray does not store the object in time before the next call and when I try to get the last inserted object, it is not the last one I inserted. There is something async happening.
Is this a known issue? How can I see if it is called in the Main Thread?

It's called on the main thread. You can check by adding a breakpoint in Xcode in -scrollViewDidScroll:, and looking at the call stack.
Alternatively NSThread has some pretty useful methods here, such as +isMainThread, or +callStackSymbols.
NSThread Docs

Related

What happens to a completion handler when a view is popped?

When a request is sent from a viewcontroller having a completion handler in place, but before the request can be received by the device, we go back to the previous view. What will happen to that completion handler block?
When are objects deallocated from memory?
Is it when the related object is moved away from the screen? Wrong!
Or is it When the related object is removed from memory? Right!
All objects are removed from memory when 'there is nothing left to strongly point to them'. This could happen when the view goes offscreen. See AutomaticReferenceCounting from docs.
Closures or completionHandlers, point to the instance. Hence they will hold the instance in memory. The instance itself will also point to the completionHandler. So both would be waiting for the other to be removed from memory. As if two people each say I would like you exit the house first. Ending result is that that none of them leave.
You need to avoid that from happening. As Sh_Khan said you do that with [weak self]. For more on why we do that. See Reference to property in closure requires explicit 'self.' to make capture semantics explicit
This case is the reason why we need to put [Weak self] in completion , to avoid strong references to that vc and so to be deallocated , if you skipped it , then what you did in completion will run but you'll not see anything as the vc's view is hidden after the pop while this instance is still in memory and will cause memory drains by time

setNeedsDisplay is submitted on main queue but is not called

The method below is called on a non-main thread, to be specific, in a recording audio queue callback
- (void)myMethod
{
//...
dispatch_async(dispatch_get_main_queue(), ^{
[myGraphView setNeedsDisplayInRect:CGRectMake(a, b, c, d)];
NSLog(#"Block called");
});
//...
}
where myGraphView is a custom UIView object. For what I know, setNeedsDisplayInRect: should be called on main thread which is why I have dispatch_async... in place. Now the problem is the method - (void)drawRect:(CGRect)rect I implemented for myGraph is never called even though the NSLog in the block has been called for many times.
There are a few possibilities here.
From the Class Reference:
Note: If your view is backed by a CAEAGLLayer object, this method has
no effect. It is intended for use only with views that use native
drawing technologies (such as UIKit and Core Graphics) to render their
content.
The other option, which is probably the cause in this case, has to do with the actual geometry. If the provided rectangle is invalid or off screen, the call does nothing. I would suggest you verify the that the rectangle is being calculated as it should be.
Thanks to #Neal's answer which led me to find out that myGraphView was, after it had been alloc-inited the first time, alloc-inited again. However, unlike the first alloc-init after which I added myGraphView to its superview, I forgot to do so after the second alloc-init.
The lesson I've learned here is that when a view is not doing what it's expected to do, such as not being displayed or updated, always check this third possibility where you forget to add it back to its superview after it's got alloc-inited again somewhere in your code. Also, if the view has a delegate you would tend to forget to set it as well.

Strange behaviour while deallocation of an object

I have a view, which is subclass of UIWebView. It has a property called Contact which is a managed object. The view uses templating engine to create a html with the object and then load into UIWebView. I thought it would be a better idea to monitor the object in the view itself, such that whenever something changes in the object, the view refreshes automatically. So, observed for certain attributes of the managed object in the view itself. And then to avoid the notification coalesce, I have made it such that the reload is done with
[self performSelector:#selector(refresh) afterDelay:0 ].
It refresh the webview automatically whenever it finds the change but also gives some strange crash. The crash says [MyWebView retain] message sent to deallocated object. I know I have properly removed observing values in dealloc method. But, it seems like dealloc gets triggered after a while. I have a strange issue related to releasing the view. The view stays for a while, although the view controller is already released and then releases after may 2/3 seconds. It is really strange. I think the crash is because of this.
Please do suggest me any idea. I will be glad to hear your suggestion. There are something wrong certainly, if anybody could point me I would really be grateful.
Using the delegate design pattern can cause EXC_BAD_ACESS KERN_INVALID_ADDRESS crashes if not used properly. If you have processing that is running in background threads that use the delegate design pattern, where in the object you set SELF as the delegate then you must remove SELF as the delegate in the dealloc method (even under ARC) by setting the delegate reference to nil, or there is a possibility that the object will try to call back into your deallocated object using the delegate design pattern. So if you have something like this in your object.
[_xmlParser setDelegate:self];
you should always have a dealloc method even under ARC to prevent the possibility of a crash in the case where your object gets destroyed while still doing work. It is very common to have your object destroyed while doing work. imagine a UIViewController that shows images from the internet. If you had a FetchImage class that used the delegate design pattern to lookup images that then calls a routine on the object when the lookup finishes, it is easily for the user to pop into and out of your UIViewController while your FetchImage object is still doing work on the background thread. You might not ever notice this when testing, but if you have hundreds of users, some of them will notice because the app will crash when your object tries to call a method on the SELF reference.
If your object uses the delegate design pattern, always have this to cleanup:
#pragma mark - dealloc - cleanup delegate references to prevent callbacks into deallocated objects (EXC_BAD_ACCESS / KERN_INVALID_ADDRESS)
- (void)dealloc
{
[_xmlParser setDelegate:nil];
// for non ARC based code you would also call: [super dealloc];
}
search every class in your project, if you have setDelegate:self or delegate = self then your users are most likely experiencing race condition crashes with your app if you don't have a dealloc cleanup method as described above. If you don't have the dealloc, add it even if you never see crashes when testing. -rrh

MBProgressHUD won't display the label

I'm using MBProgressBar in my app to display feedback whenever there is a call to a certain webService.
To do so, in the method "requestStarted" of ASIHTTPRequest, I call:
[NSThread detachNewThreadSelector:#selector(startLoader) toTarget:self];
Where startLoader is the method that pops the HUD.
Now, the thing is that whenever I call startLoader directly, the HUD gets displayed with no problem, but when I call the method using the detachNewThreadSelector thing (which is needed), the HUD is displayed but with no text label.
If I had to guess, I would say I need to force-refresh the component, but I don't know how to do that.
Anything having to do with the HUD will need to be done on the main/UI thread. If you are detach and put on a background thread, the HUD will likely never get those updates because your request will finish before getting back around to the main thread.

UITableViewCell getting _accessibilityUpdateRemoveControl on deallocated instance

Edit: While my comments have an iOS 5 working example, I am still getting this for other versions. I've now implememted a test to only register and dequeue cells if iOS 5, but it's really puzzling!
still receiving _accessibilityUpdateRemoveControl exceptions, strange nuisance, appears to be something with the edit controls, nothing is retained so nothing needs deallocing, but will try, and post the answer if I find it!
This was working yesterday, and now it's not... I changed nothing!
Edit: Turns out, while reloadData causes the crash, the crash does not occur without my custom tableViewCell... hmmm, something about removing the + sign, but it doesn't happen with deletion!
Actual error is this:
[CustomTableViewCell _accessibilityUpdateRemoveControl]: message sent to deallocated instance.
What's funny is, the remove button works. Essentially it removes the item from an array, adds it to another, basically putting it "to another table". No crashing, works fine.
If I remove the line that reloads the data in the table, after the insert button adds it, it also works. Eg: Don't immediately reload the data, close window, come back, everything displays fine. The exact line, so far, that crashes it is in
[theTable reloadData], but that line, for the other table (as I update both) doesn't crash at all. Actually, thanks to that, I'm gonna view the headers for UITableView's functions, and view other answers with that specific line. I just didn't see this, anywhere, after searching for that weird function call.
I'm ensuring my cell is within memory, and even quit dequeuing just to ensure it's working. I'm stumped with this, hopefully will have solution in an hr or less.
Thanks
I stepped through Apple's code, line by line, read the name of every function and noticed this:
editControlWasClicked: (id) clicked
is called just before crashing. I combined that with the error message, and the fact I call [table2 reloadData] before this is called, and pieced those pieces together.
The cell is erased (so it moves to the other table), but somehow calls its system callBack "editControlWasClicked" after the table reloads... since it's on the main thread, I'm guessing the table stuff is multi-threaded... how else would it call these in order but do that After the reload??
So to test this, I used the "afterDelay" function, and low and behold, it worked.
You may be asking why I'm using an add edit control in one and subtract in the other... there is a purpose to that.
So, possible solutions: 1) use the afterDelay method of selectors.
2) Write a custom IBAction ('cause it's a xib) or otherwise use custom images and functions to ensure that doesn't get called back.
Note, 2 involves writing an extra delegate so that messages from the cell can reach the view controller.
Basic solution: use iOS 5, use the queuing, otherwise do one of the above solutions or figure out the threading/hooks and find a way to do this without delaying. (I would prefer such if I can find it)

Resources