Re: Advanced Techniques
Re: Advanced Techniques
- Subject: Re: Advanced Techniques
- From: Andreas Grosam <email@hidden>
- Date: Mon, 15 Jul 2013 11:55:49 +0200
On 14.07.2013, at 01:09, Arved von Brasch <email@hidden> wrote:
> Hello list,
>
> I'm hoping the list might have some recommendations on books or other sources. My web searches aren't turning up too much that is helpful, as so much is geared towards iOS these days.
What have you searched so far?
There are really a *host* of resources available in the web, from academic ones (aka, "Asynchronous Programming Design Patterns", "Functional Programming", ) to specific solutions for particular implementation techniques (Blocks in clang). But you shouldn't stick to search for common problems in the realm of Objective-C or Cocoa. These are common language problems and how they are implemented in a particular language with the help of frameworks, is another.
Though, what no resource in the web and no book can tell you is how you would get the "grasp" to "think asynchronous" which is required to switch from synchronous programming style to asynchronous programming style. That's not unlike undertaking the challenge to switch from structured programming to OO programming style, or from imperative programming style to functional programming style.
But once you understood the principle of "thinking asynchronous" (and you don't really need a book with 350 pages to get to this point) you're likely only left with specific questions. E.g. "How to avoid circular references in a block", or, since you specifically requested "advanced techniques", you may be interested in how to implement certain asynchronous patterns, like an *asynchronous* method with the following signature:
-(void) asyncForEach:(block_t):task completion:(completion_t)completion queue:(dispatch_queue_t)queue";
which is implemented in a category of a NSArray, whose elements will be asynchronously processed in sequence by an asynchronous task, executing on a specified queue. ;)
Employing the asynchronous programming style in conjunction with the right implementation techniques (e.g. dispatch lib, Blocks, NSOperation and NSOperationQueue) also may solve all your mentioned issues in your current application. That is, if you use dispatch lib or NSOperationQueue, you automatically utilize multiple threads, you don't block the main thread, your application runs faster, and user experience will be great.
So, let's start "thinking asynchronous" through an example:
Starting with the synchronous version of a method (fetchResult) which returns a result and a client that needs that result in order to do something with it (initializing a label):
Synchronous Version
- (void) foo {
id result = [self fetchResult];
self.label.text = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}
Now, asynchronous:
An asynchronous method requires a means to notify the call-site when the result is eventually available. There are a couple of implementation techniques like Delegates, Promises (Futures), or callbacks which implement this "observer pattern". I'm illustrating the callback technique utilizing Blocks:
Asynchronous Version - implemented via Blocks as the "observer mechanism":
- (void) foo {
[self asyncFetchResultWithCompletion:^(id result){
self.label.text = [[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding];
}];
}
The difference between invoking method `foo` in the synchronous version and the asynchronous versions is the following:
In the first version, `foo` invokes the *synchronous* method `fetchResult`. `fetchResult` returns a result object which is used to set the label's text. The method `foo` will not return until after `fetchResult` will return itself - even if method `fetchResult ` is a long running operation.
In the asynchronous version, `foo` invokes the *asynchronous* method `asyncFetchResultWithCompletion :`. This method will return *immediately*. This also means, that when `foo` returns, the label is not yet set. Once `asyncFetchResultWithCompletion :` finishes (at an indeterminable time), it signals its result via calling the completion block which has been provided by the call-site and passes its result via parameter _result_ of the block. Note that when this happens, the method `foo` possibly returned already a "long" time ago. The asynchronous method does not know what the call-site is doing with the result - it just calls the provided block *when* it is finished and the result is available. The call-site on the other hand does not know *when* the result is available, but it knowns exactly *what* to do with the result, and does this through defining the block.
In brief, when `foo` returns, self.label.text has not been set yet. It will eventually be set when the asynchronous method `asyncFetchResultWithCompletion:` eventually finished.
Basically, that's it to get to the point where you have specific questions. Well, there are indeed a number of gotchas when employing the asynchronous style, which also depend on which implementation technique you use.
Regards
Andreas
>
> I have a MacOS X app that was written quite naively some time ago (small, non-public release, for MacOS 10.5). Data sets have grown considerably since it was written, and the problem of responsive interface is now quite glaring. It is a Core Data based app that makes heavy use of stored images and large amounts of text. The images, at least, aren't stored in the Core Data database, rather a file system link is saved to them. This is also true for the larger text stores.
>
> The troubles are particularly with the length of time it takes to open the views that show the images. This is an NSTableView and NSCollectionView that are loaded from the nib at the same time. Saving changes to the text files also takes a lot longer than it should, given the speed that TextEdit can save.
>
> The way I understand it, the NSTableView is probably not the problem, as NSTableViews already loads lazily. NSCollectionView, however, loads everything up front. Looking at other class options, I think what's going to be required is writing a modified NSCollectionView that does lazy loading. I haven't had to do something like that before, and I'm not sure how to approach it.
>
> The other optimisation steps that are required is otherwise mostly going to fall in the "taking advantage of multiple threads" variety. At the moment everything is done on the main thread. Saving and disk heavy access should definitely be done on background threads. I don't have much experience with GCD, and it isn't clear to me how to retrofit this into the existing code. Some architectural changes may be necessary, in order to better take advantage of threads, and the improvements to the OS since Leopard.
>
> So, I'm looking for resources that can help guide from the naive approach to more advanced techniques. I'd appreciate any suggestions.
>
> Thank you,
> Arved
_______________________________________________
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