对于想了解objective-c–启动自动释放的NSOperationQueue是否有危险?的读者,本文将是一篇不可错过的文章,并且为您提供关于CocoaTutorial:NSOperationand
对于想了解objective-c – 启动自动释放的NSOperationQueue是否有危险?的读者,本文将是一篇不可错过的文章,并且为您提供关于Cocoa Tutorial: NSOperation and NSOperationQueue、Cocoa: NSOperation和NSOperationQueue、iOS GCD 与 NSOperationQueue对比、ios – NSOperationQueue addOperations waitUntilFinished的有价值信息。
本文目录一览:- objective-c – 启动自动释放的NSOperationQueue是否有危险?
- Cocoa Tutorial: NSOperation and NSOperationQueue
- Cocoa: NSOperation和NSOperationQueue
- iOS GCD 与 NSOperationQueue对比
- ios – NSOperationQueue addOperations waitUntilFinished
objective-c – 启动自动释放的NSOperationQueue是否有危险?
喜欢这个:
NSInvocationoperation *theTask = [NSInvocationoperation alloc];theTask = [theTask initWithTarget:self selector:@selector(doTask:) object:nil];NSOperationQueue *operationQueue = [[NSOperationQueue new] autorelease];[operationQueue addOperation:theTask];[theTask release];
我很担心,但是.这是否保证工作?或者可能在某个时候运行Queue被取消分配,并采用该方法吗?
解决方法
Cocoa Tutorial: NSOperation and NSOperationQueue
Threading is hard in any language. And what is worse,when it goes wrong,it usually goes wrong in a very bad way. Because of this,programmers either avoid threading completely (and refer to it as the spawn of the devil) or spend a LOT of time making sure that everything is perfect.
Fortunately,Apple has made a lot of progress in OS X 10.5 Leopard. NSThread itself has received a number of very useful new methods that make threading easier. In addition,they have introduced two new objects: NSOperation and NSOperationQueue.
In this Tutorial I will walk through a basic example that shows how to use these new Objects and how they make multi-threading your application nearly trivial.
You can get the example project here: Async Downloader Example Project
In this tutorial,I will demonstrate one way in which to use NSOperation and NSOperationQueue to handle tasks that are best performed on background threads. The intent of this tutorial is to demonstrate a basic use of these classes and is not intentioned to be the only way to use them.
If you are familiar with Java,or one of its variants,the NSOperation object is very similar to the java.lang.Runnable interface. Like,in Java’s Runnable interface,the NSOperation object is designed to be extended. Also like Java’s Runnable,there is a minimum of one method to override. For NSOperation that method is -(void)main. One of the easiest ways to use an NSOperation is to load it into an NSOperationQueue. As soon as the operation is loaded into the queue,the queue will kick it off and begin processing. As soon as the operation is complete the queue will release it.
NSOperation Example
In this example,I have written an NSOperation that fetches a webpage as a string,parses it into an NSXMLDocument and then passes that NSXMLDocument back to the main thread in the application before completing.
PageLoadOperation.h
1 2 3 4 5 6 7 8 9 10 11 12 |
#import <Cocoa/Cocoa.h> @interface PageLoadOperation : NSOperation { NSURL *targetURL; } @property(retain) NSURL *targetURL; - (id)initWithURL:(NSURL*)url; @end |
PageLoadOperation.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
#import "PageLoadOperation.h" #import "AppDelegate.h" @implementation PageLoadOperation @synthesize targetURL; - (id)initWithURL:(NSURL*)url; { if (![super init]) return nil; [self setTargetURL:url]; return self; } - (void)dealloc { [targetURL release],targetURL = nil; [super dealloc]; } - (void)main { Nsstring *webpageString = [[[Nsstring alloc] initWithContentsOfURL:[self targetURL]] autorelease]; NSError *error = nil; NSXMLDocument *document = [[NSXMLDocument alloc] initWithXMLString:webpageString options:NSXMLDocumentTidyHTML error:&error]; if (!document) { NSLog(@"%s Error loading document (%@): %@",_cmd,[[self targetURL] absoluteString],error); return; } [[AppDelegate shared] performSelectorOnMainThread:@selector(pageLoaded:) withObject:document waitUntilDone:YES]; [document release]; } @end |
As you can see,this class is very simple. It accepts a URL in the init and stores it. When the main method is called it constructs a string from the URL and then passes that string into the init of an NSXMLDocument. If there is no error with the loading of the xml document,it is then passed back to the AppDelegate,on the main thread,and the task is complete. When the main method of the NSOperation ends the queue will automatically release the object.
AppDelegate.h
1 2 3 4 5 6 7 8 9 10 |
#import <Cocoa/Cocoa.h> @interface AppDelegate : NSObject { NSOperationQueue *queue; } + (id)shared; - (void)pageLoaded:(NSXMLDocument*)document; @end |
AppDelegate.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
#import "AppDelegate.h" #import "PageLoadOperation.h" @implementation AppDelegate static AppDelegate *shared; static NSArray *urlArray; - (id)init { if (shared) { [self autorelease]; return shared; } if (![super init]) return nil; NSMutableArray *array = [[NSMutableArray alloc] init]; [array addobject:@"http://www.google.com"]; [array addobject:@"http://www.apple.com"]; [array addobject:@"http://www.yahoo.com"]; [array addobject:@"http://www.zarrastudios.com"]; [array addobject:@"http://www.macosxhints.com"]; urlArray = array; queue = [[NSOperationQueue alloc] init]; shared = self; return self; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { for (Nsstring *urlString in urlArray) { NSURL *url = [NSURL URLWithString:urlString]; PageLoadOperation *plo = [[PageLoadOperation alloc] initWithURL:url]; [queue addOperation:plo]; [plo release]; } } - (void)dealloc { [queue release],queue = nil; [super dealloc]; } + (id)shared; { if (!shared) { [[AppDelegate alloc] init]; } return shared; } - (void)pageLoaded:(NSXMLDocument*)document; { NSLog(@"%s Do something with the XMLDocument: %@",document); } @end |
In this example AppDelegate,two things are occurring. First,in the init method,the NSOperationQueue is being initialized and an array of urls is being loaded. Then when the application has completed its load,the applicationDidFinishLaunching: method is called by the NSApplication instance and the AppDelegate loops over the urls,creating a task for each one and loading those tasks into the NSOperationQueue. As soon as each item is loaded into the queue the queue will kick it off by assigning it to a NSThread and the thread will then run the main method of the operation. Once the operation is complete the thread will report back to the queue and the queue will release the operation.
NSOperationQueue Concurrency
In this very simple example,it is quite difficult to load up the queue with enough objects to actually see it running them in parallel. However,if you run tasks that take more time than these,you will see that the queue will run all of the tasks at the same time. Fortunately,if you want to limit how many tasks are running in parallel you can alter the init method in the App Delegate as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
- (id)init { if (shared) { [self autorelease]; return shared; } if (![super init]) return nil; NSMutableArray *array = [[NSMutableArray alloc] init]; [array addobject:@"http://www.google.com"]; [array addobject:@"http://www.apple.com"]; [array addobject:@"http://www.yahoo.com"]; [array addobject:@"http://www.zarrastudios.com"]; [array addobject:@"http://www.macosxhints.com"]; urlArray = array; queue = [[NSOperationQueue alloc] init]; [queue setMaxConcurrentOperationCount:2]; shared = self; return self; } |
In this updated init method,the queue is throttled down to 2 operations running at the same time. The rest of the operations will wait until one of the first two is completed and then they will get an opportunity to run until the queue is empty.
Conclusion
That is the NSOperation and NSOperationQueue in its most basic form. You will note that most of the code in this example has nothing to do with the building up or using of the NSOperation or the NSOperationQueue. The actual code required to use the NSOperation is amazingly small. Yet with this small amount of code you can easily start using multiple threads in your application and provide a better experience for the user and be able to fine tune those complicated tasks.
Cocoa: NSOperation和NSOperationQueue
Cocoa: NSOperation和NSOperationQueue
在任何语言中多线程处理都是麻烦的。更糟糕的是如果出错了往往会以很坏的方式出错。鉴于此,程序员要么完全避免使用多线程(把它当做邪恶之源),要么发很长的时间来确保每个方面都很完美。
- #import <Cocoa/Cocoa.h>
- @interface PageLoadOperation : NSOperation {
- NSURL *targetURL;
- }
- @property(retain) NSURL *targetURL;
- - (id)initWithURL:(NSURL*)url;
- @end
PageLoadOperation.m
- #import "PageLoadOperation.h"
- #import "AppDelegate.h"
- @implementation PageLoadOperation
- @synthesize targetURL;
- - (id)initWithURL:(NSURL*)url;
- {
- if (![super init]) return nil;
- [self setTargetURL:url];
- return self;
- }
- - (void)dealloc {
- [targetURL release], targetURL = nil;
- [super dealloc];
- }
- - (void)main {
- Nsstring *webpageString = [[[Nsstring alloc] initWithContentsOfURL:[self targetURL]] autorelease];
- NSError *error = nil;
- NSXMLDocument *document = [[NSXMLDocument alloc] initWithXMLString:webpageString
- options:NSXMLDocumentTidyHTML
- error:&error];
- if (!document) {
- NSLog(@"%s Error loading document (%@): %@", _cmd, [[self targetURL] absoluteString], error);
- return;
- }
- [[AppDelegate shared] performSelectorOnMainThread:@selector(pageLoaded:)
- withObject:document
- waitUntilDone:YES];
- [document release];
- }
- @end
- #import <Cocoa/Cocoa.h>
- @interface AppDelegate : NSObject {
- NSOperationQueue *queue;
- }
- + (id)shared;
- - (void)pageLoaded:(NSXMLDocument*)document;
- @end
- #import "AppDelegate.h"
- #import "PageLoadOperation.h"
- @implementation AppDelegate
- static AppDelegate *shared;
- static NSArray *urlArray;
- - (id)init
- {
- if (shared) {
- [self autorelease];
- return shared;
- }
- if (![super init]) return nil;
- NSMutableArray *array = [[NSMutableArray alloc] init];
- [array addobject:@"http://www.google.com"];
- [array addobject:@"http://www.apple.com"];
- [array addobject:@"http://www.yahoo.com"];
- [array addobject:@"http://www.zarrastudios.com"];
- [array addobject:@"http://www.macosxhints.com"];
- urlArray = array;
- queue = [[NSOperationQueue alloc] init];
- shared = self;
- return self;
- }
- - (void)applicationDidFinishLaunching:(NSNotification *)aNotification
- {
- for (Nsstring *urlString in urlArray) {
- NSURL *url = [NSURL URLWithString:urlString];
- PageLoadOperation *plo = [[PageLoadOperation alloc] initWithURL:url];
- [queue addOperation:plo];
- [plo release];
- }
- }
- - (void)dealloc
- {
- [queue release], queue = nil;
- [super dealloc];
- }
- + (id)shared;
- {
- if (!shared) {
- [[AppDelegate alloc] init];
- }
- return shared;
- }
- - (void)pageLoaded:(NSXMLDocument*)document;
- {
- NSLog(@"%s Do something with the XMLDocument: %@", document);
- }
- @end
- - (id)init
- {
- if (shared) {
- [self autorelease];
- return shared;
- }
- if (![super init]) return nil;
- NSMutableArray *array = [[NSMutableArray alloc] init];
- [array addobject:@"http://www.google.com"];
- [array addobject:@"http://www.apple.com"];
- [array addobject:@"http://www.yahoo.com"];
- [array addobject:@"http://www.zarrastudios.com"];
- [array addobject:@"http://www.macosxhints.com"];
- urlArray = array;
- queue = [[NSOperationQueue alloc] init];
- [queue setMaxConcurrentOperationCount:2];
- shared = self;
- return self;
- }
iOS GCD 与 NSOperationQueue对比
- NSOperationQueue 是在GCD基础上实现的,只不过是GCD更高一层的抽象。
- GCD 只支持FIFO 的队列, 而NSOperationQueue可以调整队列的执行顺序。(通过调整权重)
- NSOperationQueue可以在Operation间设置依赖关系,而GCD不可以。 如果一个Operation依赖另一个Operation所产生的数据的化,你可以设置一个Operation依赖于另一个Operation来实现, NSOperationQueue可以根据依赖关系,可以以正确的顺序执行Queue中的Operation。
- NSOperationQueue支持KVO。 这就意味着你可以观察任务的状态属性。
以上几点并不是说在任何处理多任务时一定要选择NSOperationQueue, 因为NSOperationQueue在执行速度上会比GCD慢。
ios – NSOperationQueue addOperations waitUntilFinished
这是我做的:
let oldify = NSOperation() oldify.completionBlock = { println("oldify") } let appendify = NSOperation() appendify.completionBlock = { println("appendify") } let nettoyify = NSOperation() nettoyify.completionBlock = { println("nettoyify") } NSOperationQueue.mainQueue().maxConcurrentOperationCount = 1 NSOperationQueue.mainQueue().addOperations([oldify,appendify,nettoyify],waitUntilFinished: true)
使用此代码,没有任何操作正在执行.当我尝试这样做时:
NSOperationQueue.mainQueue().maxConcurrentOperationCount = 1 NSOperationQueue.mainQueue().addOperation(oldify) NSOperationQueue.mainQueue().addOperation(appendify) NSOperationQueue.mainQueue().addOperation(nettoyify)
操作执行但不按正确的顺序执行.
有谁知道我做错了什么?我对NSOperations迅速而又全新地充满信心
解决方法
>您正在检查完成块处理程序的行为.正如completionBlock文档所说:
The exact execution context for your completion block is not guaranteed but is typically a secondary thread. Therefore,you should not use this block to do any work that requires a very specific execution context.
队列将自己管理操作,但不管理它们的完成块(缺少确保操作在其completionBlock启动之前完成).因此,底线,不要做任何关于(a)运行完成块的时间,(b)一个操作的completionBlock与其他操作或其completionBlock块等的关系,以及(c)它们在哪个线程上执行的假设. .
>操作通常按照添加到队列的顺序执行.但是,如果添加一组操作,则文档不会正式保证它们按照它们在该数组中出现的顺序排队.因此,您可能希望一次添加一个操作.
>话虽如此,文档继续警告我们:
An operation queue executes its queued operation objects based on their priority and readiness. If all of the queued operation objects have the same priority and are ready to execute when they are put in the queue—that is,their
isReady
method returnsYES
—they are executed in the order in which they were submitted to the queue. However,you should never rely on queue semantics to ensure a specific execution order of operation objects. Changes in the readiness of an operation can change the resulting execution order. If you need operations to execute in a specific order,use operation-level dependencies as defined by theNSOperation
class.
要建立显式依赖关系,您可能会执行以下操作:
let oldify = NSBlockOperation() { NSLog("oldify") } oldify.completionBlock = { NSLog("oldify completion") } let appendify = NSBlockOperation() { NSLog("appendify") } appendify.completionBlock = { NSLog("appendify completion") } appendify.addDependency(oldify) let nettoyify = NSBlockOperation() { NSLog("nettoyify") } nettoyify.completionBlock = { NSLog("nettoyify completion") } nettoyify.addDependency(appendify) let queue = NSOperationQueue() queue.addOperations([oldify,waitUntilFinished: false)
>顺便说一下,正如您将在上面看到的那样,您不应该将操作与waitUntilFinished一起添加到主队列中.可以随意将它们添加到不同的队列,但不要使用waitUntilFinished选项从串行队列调度回自身.
关于objective-c – 启动自动释放的NSOperationQueue是否有危险?的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于Cocoa Tutorial: NSOperation and NSOperationQueue、Cocoa: NSOperation和NSOperationQueue、iOS GCD 与 NSOperationQueue对比、ios – NSOperationQueue addOperations waitUntilFinished的相关知识,请在本站寻找。
本文标签: