Re: Progress Indicators Spin vs Bar
Re: Progress Indicators Spin vs Bar
- Subject: Re: Progress Indicators Spin vs Bar
- From: James Merkel <email@hidden>
- Date: Mon, 20 Jun 2011 20:43:36 -0700
On Jun 20, 2011, at 7:23 PM, Conrad Shultz wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
On 6/20/11 3:54 PM, James Merkel wrote:
I'm opening all digital camera files in a folder (JPEG, TIF, etc),
extracting a thumbnail and some Exif data, and putting the data in a
TableView. The time consuming part is finding the thumbnails in the
files.
OK.
I don't know anything about extracting thumbnails et al., but for the
sake of argument suppose you have a class JMImageProcessor that has
methods like:
- - (id)initWithFileHandle:(NSFileHandle *)fileHandle;
- - (NSDictionary *)exifData;
- - (NSImage *)thumbnail; // Takes a long time to run
So in your main thread you then have a loop over a bunch of
NSFileHandles (of course you might be accessing the files completely
differently; this is just for illustration). So you might currently
have:
for (NSFileHandle *fileHandle in files) {
JMImageProcessor *processor = [[JMImageProcessor alloc]
initWithFileHandle:fileHandle];
// Call some code to stash the results, presumably updating the
tableView's data source in the process
[self setExifData:[processor exifData] forFile:fileHandle];
[self setThumbnail:[processor thumbnail] forFile:fileHandle];
[processor release];
// Call some code to redisplay the NSTableView
[self updateTable];
}
You could make such code non-blocking with, for example, GCD:
dispatch_queue_t workerQueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL);
for (NSFileHandle *fileHandle in files) {
dispatch_async(workerQueue,
^{
JMImageProcessor *processor = [[JMImageProcessor alloc]
initWithFileHandle:fileHandle];
[self setExifData:[processor exifData] forFile:fileHandle];
[self setThumbnail:[processor thumbnail] forFile:fileHandle];
[processor release];
dispatch_async(dispatch_get_main_queue(),
^{
[self updateTable];
// UI updates need to be on the main thread, i.e., the GCD main
queue, so we call back asynchronously
}
);
}
);
}
(Note 1: this was all written in a mail client and untested.)
(Note 2: the above assumes that the setExifData/setThumbnail methods
are
implemented properly, atomically if required. But if the methods are
backed by, for example, mutable dictionaries, and anything accessing
them handle absent entries reasonably, this should be pretty
straightforward.)
(Note 3: this could all alternatively be done with NSOperationQueue,
or
even plain old NSThread. But GCD can probably do it in the smallest
amount of code.)
Good luck!
- --
Conrad Shultz
Synthetiq Solutions
www.synthetiqsolutions.com
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.7 (Darwin)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
iD8DBQFOAACvaOlrz5+0JdURAvzkAJ9XaQ4CqRXY4k6fKtRdVkqcYBeBewCeL8fh
jOJSgWEisHfOU6/WflFoukA=
=swOg
-----END PGP SIGNATURE-----
First of all (kind of basic) what is GCD ?
I have actually implemented this a couple of different ways (not using
threads).
At first I just had lazy loading of the TableView. Whenever the
TableView needed something a file was accessed and a thumbnail
extracted. Then I changed it to do preprocessing. That is, everything
was extracted from the files and then the TableView was allowed to
load. The first approach uses less memory but is slower in updating
the TableView (when it is scrolled for example). The second approach
uses more memory but is faster in updating (provides a better user
experience). I think trying to do this in a separate thread would be
much cleaner using the second approach.
I forgot to mention the really slow case: if a thumbnail can't be
found in the file, then I make a thumbnail from the main image. If
this has to be done on a lot of files, then things really bog down.
Jim Merkel
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden