NSOperationQueue Problem

Discussion in 'iOS Programming' started by walty, Sep 29, 2008.

  1. walty macrumors member

    Joined:
    Jul 15, 2008
    #1
    OK, this is really desperate and painful, and I am now stuck and hungry in office :(


    Basically, I only need to run some operations on IPhone after the execution of main UI thread. And I used NSOperation and NSOperationQueue for this. I checked the SDK, and here is what I wrote for testing this behaviour:


    I got a simple class inherit from NSOperations

    TestLoader.h
    Code:
    
    #import <UIKit/UIKit.h>
    
    
    @interface TestLoader : NSOperation {
    	bool running,started;
    	int threadID;
    }
    
    -(id)initWithThreadID:(int)threadID_;
    
    @end
    
    TestLoader.m
    Code:
    
    
    #import "TestLoader.h"
    
    
    @implementation TestLoader
    -(id)initWithThreadID:(int)threadID_
    {
    	self = [super init];
    	running = FALSE;
    	started = FALSE;
    	threadID = threadID_;
    	return self;
    }
    
    - (BOOL)isExecuting
    {
    	return running;
    }
    
    - (BOOL)isFinished
    {
    	return started && !running;
    }
    
    - (void)start
    {
    	running = true;
    	started = TRUE;
    	
    	sleep(3);
    	for(int i=0; i<10; i++)
    		NSLog(@"@17,inside thread %d ", threadID);
    	
    	running = false;
    	
    }
    
    - (BOOL)isConcurrent
    {
    	return YES;
    }
    
    
    and then in my appDelegate.m, I put this into applicationDidFinishLaunching

    Code:
    
    //queue is of NSOperationQueue object and is instantiated in init:
    
    	[queue setMaxConcurrentOperationCount:2];
    	TestLoader *loader = [[TestLoader alloc]initWithThreadID:1];
    	[queue addOperation:loader];
    	NSLog(@"@53,add new thread");
    	[queue addOperation:[[TestLoader alloc]initWithThreadID:2]];
    	[loader release];
    	NSLog(@"@37, about to quite main thread");
    
    

    and this is the output:

    Code:
    
    2008-09-29 20:03:04.273 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.275 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.278 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.278 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.279 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.279 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.280 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.280 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.281 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.281 Rosetta[13090:20b] @17,inside thread 1 
    2008-09-29 20:03:04.282 Rosetta[13090:20b] @53,add new thread
    2008-09-29 20:03:07.282 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.284 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.284 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.285 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.286 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.287 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.287 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.288 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.288 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.289 Rosetta[13090:20b] @17,inside thread 2 
    2008-09-29 20:03:07.289 Rosetta[13090:20b] @37, about to quite main thread
    
    
    
    so, basically:

    1. the main thread is blocked until all 2 threads are done
    2. the second thread is not added until first thread is done


    I googled around for 2 hours, and found some sample code in Cocoa, but none is for iPhone, anyone any hint please?!!!

    thanks a lot
     
  2. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #2
    Did you actually read the documentation?

    Quoting from http://developer.apple.com/document...OperationQueue_class/Reference/Reference.html

    "If the isConcurrent method of an operation returns NO, the operation queue automatically creates a new thread for that operation before running it. If the isConcurrent method returns YES, the operation object must create its own thread or otherwise configure its own runtime environment as part of its execution phase."

    You are returning YES for isConcrrent so it's up to you to start a thread. As you aren't starting a thread each NSOperation will block the calling thread until it is complete which is exactly what we see with your output.
     
  3. walty thread starter macrumors member

    Joined:
    Jul 15, 2008
    #3
    OK, hm... works now, STUPID ME!!!!

    Last night, I just focused on checking the documentation of NSOperation, which say that


    And last night I have tried to manually trigger the NSOperation, and then tried to insert them into NSOperationQueue, actually I have read the mentioned line once, just I am not quite sure what it means when I read it. Actually, I could be more carefully, I should find the following in the heading of NSOperation doucmentation:

    Which basically, I need to explicitly create the thread myself anyway if I use concurrent operation..

    May be next time, when I stuck too long, I should just go home and watch TV..


    Finally, REALLY REALLY THANKS A LOT!!!


     
  4. robbieduncan Moderator emeritus

    robbieduncan

    Joined:
    Jul 24, 2002
    Location:
    London
    #4
    This is a really good idea. Sometimes what you need is a break from staring at the same, seemingly correct code. If you go do something else and come back with fresh eyes often times the mistake suddenly becomes clear :)
     
  5. youPhone macrumors member

    Joined:
    Sep 8, 2008
    #5
    This post is supposed to help keep people from making the same stupid mistake I just made and fixed.

    I started writing a reply where I was getting the behavior:
    I used this same example, but added a 3rd operation to the queue and I changed isConcurrent to YES. Only the first two threads were running and the 3rd never did.

    After writing the whole reply (and I had been working on the problem for a couple hours -- even reading the docs over), I decided to check the the NSOperation and NSOperationQueue docs one more time.

    It turns out, when you're going to concurrent=NO, you ("typically") need to only override the main function and not all of the others (start, isConcurrent, isExecuting, isFinished)........as it says in the documentation. :rolleyes:

    After commenting out those functions and moving the logic from "start" to "main", it was all working like it should be.

    Another lesson in reading the documentation one last time before posting.

    Hope this helps.
     

Share This Page