Skip to content

Working with NSOperationQueue

jballanc edited this page Nov 26, 2012 · 1 revision

When you're using NSOperationQueue, you don't want/have to deal with NSThread, the system creates and controls the threads for you. When you specify the number of concurrent operations (queue#maxConcurrentOperationCount = 4), the system will run 4 operations at the same time on 4 different "threads".

Let's say you want to run 4 different operations at the same time on the MainQueue. Unfortunately, this isn't possible. Since the MainQueue is not a concurrent queue, it only runs an operation per time.

puts NSOperationQueue.mainQueue.maxConcurrentOperationCount    # => 1

Instead here is how you can have multiple operations processing at once, step by step.

# we create our methods that represents an operation each. 
def thread1
  10.times { |i| NSLog("\t Thread1: #{i}") }
end

def thread2
  20.times { |i| NSLog("\t\t  Thread2: #{i}") }
end

def thread3
  30.times { |i| NSLog("\t\t\t   Thread3: #{i}") }
end

def viewDidLoad
  # we create an concurrent queue
  queue = NSOperationQueue.new
  # we set the max number of concurrent operations
  # default is as much as possible NSOperationQueueDefaultMaxConcurrentOperationCount, but you only need 3 :-)
  queue.maxConcurrentOperationCount = 3 
  # we give the queue a name, just to trace them       
  queue.name = "threads operation"

  # we create our operation
  operation1 = NSInvocationOperation.alloc.initWithTarget(self, selector: :thread1, object:nil)
  operation2 = NSInvocationOperation.alloc.initWithTarget(self, selector: :thread2, object:nil)
  operation3 = NSInvocationOperation.alloc.initWithTarget(self, selector: :thread3, object:nil)

  # if you're running as a script you should not uncomment this line, since you script runs on the mainQueue, you'll see nothing
  # but if you're running in a cocoa application, you will see the results.
  # and by the you don't really need it at all (SOLUTION 2)
  # NSOperationQueue.mainQueue.addOperationWithBlock(->{ 
    queue.addOperation(operation1)
    queue.addOperation(operation2)
    queue.addOperation(operation3)
  # })
end

viewDidLoad
# running as script you need to sleep, otherwise you script will not wait for the concurrent operations running in you queue
sleep 10.0

SOLUTION 2

if you want the results of the operations to be executed on the mainQueue, you can do this:

# it may act differently if you run it as an application or a script
def thread1
  # heavy works…
  10.times do |i| 
     NSOperationQueue.mainQueue.addOperationWithBlock(lambda { NSLog("\t Thread1: #{i}") })
  end
end

I hope it helps you to understand a little on how to use NSOperationQueue, if you want to learn more take a look into apple's Concurrency Programming Guide.

This page is derived from an excellent response to issue #160 by @seanlilmateus