开发者

Execute a method that takes a second to complete without temporarily halting code

Basically, i have a method that takes a few seconds to complete as it copies some files using NSFileManager. This is invoked on the touchesMoved event when the user picks up a draggable UIView icon. However, there's a slight delay before the icon's position is updated. I'm guessing it's waiting for that method to copy it's files before continuing. The method HAS to be triggered on touchesMoved, so please don't suggest moving it.

How can开发者_运维技巧 i execute a method that takes about a second to complete, without holding up the code?

(..and don't worry the copy method doesn't get repeatedly called from the touchesMoved event)


You could perform the task in the background using performSelectorInBackground:...:

http://developer.apple.com/library/ios/#documentation/Cocoa/Reference/Foundation/Classes/NSObject_Class/Reference/Reference.html

This prevent that selector from blocking the main thread.

Example:

[self performSelectorInBackground:@selector(myMethod) withObject:nil];


Do it in a background thread. Leave the main thread to deal with UI stuff only.


Technically you could divide the copying of files into very small chunks, and tell the current NSRunLoop to dispatch between each file copy.

But practically just say no to any IO access on the main thread, all IO access should be done in the background. Even the slightest block on the main thread will make the UI stutter and be unresponsive, Android user might accept that, iOS user do not.

Your options are numerous, and easy to implement. You could do a simple performSelector–:

-(void)backgroundWorker {
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  // Do your stuff
  [pool release];
}

-(void)startDoingIOStuff {
  [self performSelectorInBackground:@selector(backgroundWorker)
                         withObject:nil];
}

You could do it practically inline using a block and GCD:

-(void)startDoingIOStuff {
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, NULL),
                 ^{
                    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
                    // Do your stuff
                    [pool release];
                  });
}

Or you could use an NSOperation on a NSOperationQueue. I have written a longer blog post on this topic, including source code that is available here: http://blog.jayway.com/2010/08/19/future-cocoa-operation/


Before immediately resorting to a secondary thread, it would certainly be worth a try to use a plain old performSelector on self. For example:

[self peformSelector:@selector(copyFiles) withObject:nil afterDelay:0.0];

Note that this is different from doing:

[self copyFiles];

The peformSelector version basically says "do copyFiles ASAP, OK?", but doesn't block everything while waiting for it to be done. In other words, it's possible that the perform selector version would allow the main event loop to update the UI (thereby preventing the apparent visual lag) before the file copying is actually done.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜