Frage

in my iOS application, I am calling a method called loadData in my viewDidLoad method.

loadData takes data from a local SQLite database and populates an array of items.

In another method, showData, I take the loaded data and show it on the actual screen.

- (void)viewDidLoad {
    [super viewDidLoad];
    [self loadData];
    [self showData];
}

- (void)loadData {
    //connects to local SQLite database
    //data is loaded into a NSMutableArray called 'myData'
}

- (void)showData {
    UIImage *myImage = [UIImage imageNamed:[myData objectAtIndex:0]];
    self.imageView.image = myImage;
}

However, this currently does not work because it takes some time for the method loadData to populate my array.

I would like to show a custom progress indicator view that pops up on the screen with a spinning image that I made. This would appear until the method loadData completes, and then showData would be run.

Could someone point me in the right direction or link me to a way to do this? Thank you so much!

War es hilfreich?

Lösung

The way to do this is to do your database retrieval asynchronously, in a background queue. This can be tricky to do multi-threaded database operations and one simple solution is to simply create a dedicated serial background queue in which you'll do all of your database interactions (thus the database operations, themselves, are running on a single thread). Thus your background process that loads the data will dispatch database operations to this queue, as will any database interactions you would otherwise do from the main queue.

If you're using FMDB, you can do this with FMDatabaseQueue, which handles all of this for you. Or you can write your own. (I'd encourage you to check out FMDB, though. If nothing else, look at how it's doing FMDatabaseQueue and adopt this pattern in your own code.)

If you do this, dispatching the initial load to a background queue that will do all database interactions through this separate dedicated serial database queue, just make sure to dispatch the UI updates of your progress indicator back to the main queue, because all UI interactions should take place on the main queue.

Having said that, there's absolutely no reason why database queries for a user interface should be so slow as to necessitate this, though. I wonder whether it's worth digging into why your database code is so slow, and you may be able to cut the Gordian knot altogether.

A typical example of inefficient database operations is when you store images in the database. Unless you're dealing with very small thumbnail images, SQLite is notoriously inefficient when dealing with BLOB data. The typical solution is to store the images in persistent storage (e.g. your Documents folder), and only save references to those paths in the database. This offers all sorts of potential optimizations.

In your comment, you mention that the database maintains URLs of images. Well, in that case, you can refrain from retrieving the images in your loadData routine, and instead employ "lazy loading" of the images, namely load the images in a just-in-time manner, only as they're needed. You can achieve this using a UIImageView category that does asynchronous loading, such as SDWebImage or, if you're already using AFNetworking, you can use its UIImageView category. If you google "lazy loading UIImage", you'll probably find tons of wonderful links, tutorials, etc. But both of these categories provide not only a easy "lazy loading" mechanism, but also provide caching of images, etc.

But the ideal scenario, rather than designing a progress view for a slow loading process, just refactor your design, completely eliminating this performance bottleneck. It would be a shame to go through the work of designing a progress view for an inefficient loading interface.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top