How do I diagnose blocking in an iOS app? - ios

So, I've got an iOS app which works nicely - usually, except the UI occasionally blocks. Is there a standard technique for diagnosing sporadically unresponsive UI?
In my case, I've got LRResty pulling data asynchronously, and the resultant data is parsed by NSXMLParser into some NSMutableArray objects.
I'd pin it on the XML parsing, but the UI doesn't block consistently in place. It blocks primarily after tapping the back button on my UINavigationBar, but also the initial table view doesn't scroll until the search bar is interacted with. Could there be a parser still working, or a request still working?

I use "Time Profiler" in instruments to see which methods are causing the unresponsive UI
(source: bmxmdb.com)
.
I just run it without touching anything, do the action in the app that you need to test, then stop recording, and after a lot of drilling down you find the offending method(s) this is my app accessing the DB.

Related

iOS Core Data sometimes is delayed in loading

I have an app that's been available in the app store for a few years that uses Core Data. When the app is launched, the user is taken to the app's home screen where a few buttons are shown. Clicking any of the buttons takes the user to another screen that shows data that is loaded from Core Data in a UITableView (each button takes the user to different data). This is basic functionality that's been working in my app just fine the entire time the app's been available.
At some point last year, I noticed that at random times, the data saved in the app sometimes wouldn't load right away. The first time this happened, I clicked one of the buttons and was taken to a blank screen. I went back to the home screen and tried other buttons, and each screen was blank, so I thought all of my data had been wiped somehow. I proceeded to head back to the home screen and just sat there thinking for about 15 seconds, then I clicked one of the buttons again, but this time the data appeared. All of the other screens had data now as well.
I haven't updated the app in quite a while, so my code is unchanged. I don't recall there being a new iOS release around the time I started observing the issue, but it's possible.
This has happened a few more times since I first discovered it (3 or 4 times total over the last 6 months), but there seems to be no pattern at all. Once the data finally loads during these situations, it always loads right away from that point forward. This has made it impossible for me to debug it, because I can't force this situation to happen (99% of the time the data loads immediately).
Has anyone encountered this before, or have any recommendations on how to proceed? I've witnessed this on the Simulator and once on an actual device.
Random delays in updating your UI are a classic sign of attempting to update the UI from outside the main queue. It'll work, usually, but it may be delayed, and the delays won't be consistent. Make sure that when you try to update the UI, you're on the main queue. Use DispatchQueue.main.async() if necessary.
Assuming that you're using Xcode 9, make sure the main thread checker is turned on. That'll help you find this kind of problem when you're running the app from Xcode. Go to the target pop-up at the top of Xcode's window and select "Edit scheme...". In the "Run" section of the window, go to "Diagnostics" and make sure "Main Thread Checker" is turned on.

How can I make a continuous action process smoothly on a device? (GCD)

I'm making a third party keyboard for iOS and without autocorrect, everything runs smooth as butter, especially on older devices such as the iPhone 5 and 4s. Unfortunately, as soon as I re-enable autocorrect, the process starts to lag on the aforementioned devices. How can I prevent this?
How I set up my autocorrect
Every time the user presses a key, the word being typed is run through a function that a) tries to complete the word b) tries to correct the word. The words completed and stored are stored in an array and the first element of each array is set as the text of the label in the suggestion bar.
The process itself is pretty quick and the results are logged almost instantly, but typing fast is when the trouble starts.
My Thoughts
Which GCD method should I use to speed things up? dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE) and dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY) seem like good candidates but I've never used GCD and would like others' opinions. Also, is there any other way of speeding up such a process? It doesn't seem like other third party keyboards are having this problem so I'm probably doing something wrong :(
Thanks in advance!
You are definitely on the right track. You should not be running the code that you want to make suggestions in the same thread that you have the user interaction as this will clog up the main thread.
So, I would call dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INTERACTIVE) to do all of your analyzation. Just remember, when you update the labels on your keyboard you have to go back to the main queue... For example.
dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) {
//do all of your code that you need to get the values for the labels.
dispatch_async(dispatch_get_main_queue(),{
//update the labels with the value you got.
})
}

UITableView freezes after deleting an entry

My app's MasterView includes a table view which is filled with 10 cells containing some core data objects like a "title" (previously downloaded from the internet, see next paragraph). Thanks to the template "Master-Detail Application" I can make use of the built-in NSFetchedResultsController and its methods which take care of the core data handling (e.g. deleting rows). When running the app, the cells get configured with the existent core data objects. At this point I can delete those entries like one would expect.
In addition, my app also has a refresh button. When tapped, it loads some new data from the internet and converts it into objects that are saved to core data. The cells configure themselves again the same way they did before and the UITableView gets a refresh. Again I can delete an entry but now, as soon as I've deleted one which then disappears normally, the table freezes (not the whole app) in the sense that its cells are not tappable anymore/don't react to gestures. I can refresh and that work (10 entries again after having deleted one before) but the cells keep being untappable. I have to stop the app to return to normal functionality.
When restarting, the one entry deleted before is - like expected - gone, 9 entries are left. Again everything works fine at this point, I can delete multiple ones without a problem. But as soon as a manual refresh took place, we're at the same point as before when deleting an entry now.
A common pattern when missing something specific? I'm happy to post some code but I have no idea right now which parts would help...
If the app is really freezing, common sources of this sort of problem are deadlocks. If you're using dispatch_sync anywhere, that's a common source of problems (notably using dispatch_sync from the main thread to something that eventually does another dispatch_sync back to the main thread). If you're using NSLock or #synchronized, and call them recursively, you can also deadlock that way, too.
Another source of problem is an infinite loop (such as an error in a while clause that is never satisfied). If you have such a loop in the main thread, that will freeze the UI. (Anything that blocks the main thread will freeze the UI.)
You might be able to diagnose where it's freezing by running the app through the debugger in Xcode, and when the app freezes, press the debugger's "pause" button. While it will often pause in the middle of some fairly cryptic assembler code, you can often look at the stack traces to figure out where the app was when it froze.
If it's simply that you're not seeing your UI updated as a result of your actions, try making sure that the reloadData method is called on the main queue, if it's not, e.g.:
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
Not sure if related, but I run into a freezing problem with table view with header and footer view that were reloaded manually after Core Data fetch request. Table view was reloaded right after the fetch and sometimes was stopping respond to touches. Delaying the tableView.reloadData() by 0.1 second fixed the problem completely.
(Without header and footer view, everything worked fine).

iPhone app Debug Is very fast but (Adhoc and appstore) Release is very slow

Does anyone know of any potential causes of chuggy slowness through out an iPhone app, as a result of some kind of config or third party library in the release version of an app?
I have libTestFlight, libGoogleAnalytics, libBlitFeedback, MKNetwork as well as Bolts, NewRelic, Parse and the Facebook SDK... everything else is a standard iOS SDK library.
When I build for Debug, she runs lightning fast... I simply change to 'archive' and release the app on test flight and walah it runs like a piece of crap.
I use images heavily which are all generally loaded by using "UIImageView+WebCache.h" and the SDWebImage package https://github.com/rs/SDWebImage.
I'm just in the process of elimation at the moment as the app never used to run chuggy, but I made a lot of changes in the space of a week which were all intended to make the app smoother and faster.
An example use case is:
User opens App.
Table View loads cells with images and text.
Network call updates data.
User taps tab bar to change to a UICollectionViewController. It reloads.
User taps Profile VC, it refreshes some data.
In Debug... this use case is lightnining fast, transitions smooth and quick on iPhone 4 or 5
In Release mode.. Tapping on the tab bar takes 3 seconds to transition. Scrolling is clunky in the tableview or collection view.
In answer to my own question, the reason was the result of dropping this particular piece of code in my release target.
https://gist.github.com/steipete/5664345
And more precisely this piece of code #define PROPERTY(propName) ##propName:
// Compile-time selector checks.
if DEBUG
define PROPERTY(propName) NSStringFromSelector(#selector(propName))
else
define PROPERTY(propName) ##propName
endif
Was found to be the cause of our problems only discovered by using profiler and realising that it was just soaking up the available CPU cycles. iPhone 4 was so slow it basically was unresponsive.
Anyway, the generic answer is to profile your app to see whats slowing the CPU down.

Setting properties of UI elements without having to restart simulator

I have a lot of UI elements on my screen, and I have to tweak their appearance to perfection including the frame, text color, background, color, corner radius, etc. Each tiny tweak means that I have to re-compile the code and restart the simulator - and it can take 5-6 seconds per iteration, which is very time consuming (and annoying) when 100's of tweaks have to be made by trial and error. My question is if there are any techniques to instantly update the properties of each UI element WITHOUT having to recompile the code and relaunch the simulator.
One technique I had in mind is to embed a UIWebView which will automatically download a json from a localhost server that contains all the UI elements and their properties. I would have Grunt Server running on my local machine and it would detect any change made to that json file and cause the UIWebView to refresh and download the new json after every edit. There would be a handler in my code which will set the UI element properties to the new values contained in that json. This way I can just have the simulator and a text editor side by the side and I can see how the changes I make in the json impact the appearance of the UI elements instantly.
Perhaps there are other developers out there who have had the same issue and can share how they overcame this annoying problem. I don't like using nib files - so please don't tell me to use nib files :) Even with .xib files, you still have to compile them.
Make a second little viewController subclass with UISliders etc you can set to do various things, rgba for a colour for example, set up a quick and dirty protocol to push these values back to root viewController and redraw element in question, then pop the second view controller modally to tweak stuff (inside a UIPopover on iPad simulator would probably be easiest. This could become a nice reusable 'skinning' class that you use in development, just need a tool item or button to trigger it)
Probably NSLog the values as well so when you finalize something you can hardcode or typedef it in

Resources