Sharing NSOperationQueue across View Controllers?

2019-03-08 21:32发布

问题:

I'm using an NSOperationQueue to manage HTTP connections (using ASI-HTTPRequest). Since I have multiple views and the need to have these different views requesting HTTP connections, should I try to create a global NSOperationQueue in the app delegate, or should I have one in each of the views? I'm not familiar with NSOperationQueue.

I'd like to know a) what the best practice is and b) if there is no best practice, what the tradeoffs are if any.

I did try to put the operation queue in the class (as a property) where I handle the server connections but the task never fired. Couldnt figure it out but [queue operations] = 0. If someone knows a solution to this, I presume this would be the best place to put it.

回答1:

I have solved this by adding a class method on NSOperationQueue that I think Apple has missed; a shared operation queue. I add this as a category on NSOperationQueue as this:

// NSOperationQueue+SharedQueue.h
@interface NSOperationQueue (SharedQueue)
+(NSOperationQueue*)sharedOperationQueue;
@end

// NSOperationQueue+SharedQueue.m
@implementation NSOperationQueue (SharedQueue)
+(NSOperationQueue*)sharedOperationQueue;
{
  static NSOperationQueue* sharedQueue = nil;
  if (sharedQueue == nil) {
    sharedQueue = [[NSOperationQueue alloc] init];
  }
  return sharedQueue;
}
@end

This way I do not need to manage a whole bunch of queues unless I really need to. I have easy access to a shared queue from all my view controllers.

I have even added a category to NSObject to make it even easier to add new operations on this shared queue:

// NSObject+SharedQueue.h
@interface NSObject (SharedQueue)
-(void)performSelectorOnBackgroundQueue:(SEL)aSelector withObject:(id)anObject;
@end

// NSObject+SharedQueue.m
@implementation NSObject (SharedQueue)
-(void)performSelectorOnBackgroundQueue:(SEL)aSelector withObject:(id)anObject;
{
  NSOperation* operation = [[NSInvocationOperation alloc] initWithTarget:self
                                                                selector:aSelector
                                                                  object:anObject];
  [[NSOperationQueue sharedOperationQueue] addOperation:operation];
  [operation release];
}
@end


回答2:

My personal preference for this is to have a singleton that manages all http requests. Each view would then ask the singleton to make the http call, passing itself as a delegate for that call then the singleton hands that delegate and call off to an NSOperation and then NSOperation calls back once the call is done.



回答3:

If you already have a pointer to a class that handles connections in each view/view controller, there's no reason you would also need to have a pointer to the operation queue.

I suppose what you want to do is something like: a) view(Controller) hands url(+data) to server handling object, b) server handling objects creates operation and puts it in a queue that it and only it has a pointer to.

It's hard to figure out why that didn't work if you don't provide more detail.

I highly recommend taking a look at ASIHTTPRequest which provides a NetworkQueue class to handle this kind of task. It has several convenient delegate fields that lets you register to keep track of progress, know when a download or upload finished etc.