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).
Related
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.
Prior to iOS 11 I was able to reload a table views data on the fly without having to dispatch the reload to the main thread. However, now that I am testing on a device that has iOS 11 installed it seems I have to dispatch every UI update to the main thread in order for it to work. Or else I end up with empty UI elements. i.e. table views with all the rows but no labels, or buttons with no titles, etc.
Does anyone know what changed in iOS 11 to require this? Is there a way to turn it off?
Since times immemorial Apple has stressed that all interactions with UI elements must happen on the main/GUI thread. Failing to heed that advice would result in weird behavior: sometimes it would work fine, other times it wouldn't. Clearly, now they've changed something to make the behavior more predictable -- it simply doesn't work any more in your specific case and perhaps more generally.
At any rate, I see no reason why one would not simply do what's spelled out in the documentation and ensure that your UI gets updated from the main thread.
When trying to develop a Today Extension for iOS 8 I found a weird issue. It would seem that the View Controller I'm using is being recreated every time the user opens Notification Center. This means that there is no data retention and hence no way for me to know if the extension needs to update or not.
The main reason for wanting to do this is that I want to preserve the height of the widget (Using preferredContentSize). The problem is that when the view loads this value always gets reset which leads to the widget jumping around in size. The Stocks widget is an example of how it's supposed to work and they've obviously solved it so there has to be some way of retaining the data between different "sessions". I can also tell from the debugger that the process continues to run, so it's just down to something in Apple's code forcing the View Controller to be recreated.
My question is, is this a bug? Or is it based on some setting or some property that I'm missing? Or is it maybe just the way it's supposed to work? If so, what is the workaround?
That's the way they work. Save your information to the device so you can reload it the next time you launch, along with the update time so you know if it's out of date. For small amounts of data, just use NSUserDefaults. For larger amounts save to a file, CoreData, sqlite, etc.
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
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.