2

I have object with .delegate property which i manipulate in method 'doJob'. I assign this property with 'self' and my function is being called when this object finishes his job. Till now everything is fine.

Now i want to manipulate this object in a separate thread.

I'm using [NSThread detachNewThreadSelector...] to run the 'doJob' function. In this case my delegate method not being called. I guess this is because 'self' points to new thread instead of main one. Ok. I'm passing self as argument to function while creating the thread and it still not working. What do i miss?

my current code is as follows:

- (void)mainFunction
{
    [NSThread detachNewThreadSelector:@selector(doJob:) toTarget:self witObject:self];
}

- (void)doJob:(MyObject*)parentThread
{
    ManipulatedObject *obj = [[ManipulatedObject alloc] init];
    obj.delegate = parentThread;
    [object startJob];
}
Misha
  • 5,260
  • 6
  • 35
  • 63
  • Do you have to use NSThread for some particular reason? There are a handful of other ways to do multi-threading in Objective-C. The best option is Grand Central Dispatch. – rbrown Aug 09 '11 at 17:02
  • I can't say because i'm not familiar with other methods. – Misha Aug 09 '11 at 17:54
  • There are three main techniques, besides NSThread. There is -performSelectorInBackground:withObject:, NSOperationQueue, and Grand Central Dispatch (GCD). GCD is by far the best option. One reason is because it uses blocks for running asynchronous code and for callbacks. It extremely easy to use. However, it is only available on iOS 4.0+ and Mac OS X 10.6+. NSOperationQueue is similar to GCD, except you use NSOperation objects instead of blocks. It's available on older systems. On a modern OS, it uses GCD underneath the covers anyway. -performSelector... is very similar to NSThread. – rbrown Aug 09 '11 at 18:58
  • If you are able to use iOS 4.0+, I can give you a much more detailed explanation about GCD. I highly recommend it. GCD makes multi-threading very easy and efficient. – rbrown Aug 09 '11 at 19:10

2 Answers2

1

GCD will make most of your multi-threading troubles trivial. You can do something like this:

- (void)mainFunction
{
    // Runs your task on a background thread with default priority.
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        ManipulatedObject * obj = [[ManipulatedObject alloc] init];

        [obj startJob];  // I'm assuming this is sychronous.

        // The callback is explicitly run on the main thread.
        dispatch_async(dispatch_get_main_queue(), ^{

            // Your callback here.

            [obj release];
        });
    });
}

That's all you have to do, it's that simple. All the relevant code is inline and together.

If you want the ManipulatedObject to explicitly invoke the block, then you could add that ability to ManipulatedObject. To do so, you should:

  1. Define the block type for convenience typedef void(^MyCallback)();

  2. Add @property (nonatomic, copy) MyCallback block; and @synthesize block. Don't forget the copy.

  3. Invoke the block when you need to dispatch_async(dispatch_get_main_queue(), [self block]);.

If your delegate needs to make more than one kind of callback, then you will need a block for each callback. It's a minor inconvenience, but it's worth it for all the conveniences you gain.

For a more thorough explanation of blocks and GCD, check out WWDC 2011 session 308.

rbrown
  • 2,635
  • 2
  • 24
  • 24
  • can you explain the code, I have the same problem. but I dont understand your code very well. please explain it more , thanks in advance. – Milad Rezazadeh Jan 05 '12 at 02:19
  • 1
    Before I can answer your question, I need to know a couple things. First, do you fully understand Objective-C blocks? Second, do you have experience with concurrency? If not, then you can check out WWDC 2011 session 308 to get up to speed. – rbrown Jan 06 '12 at 23:27
0

Well firstly you do not need to pass self as the witObject: parameter, (which is spelt wrong) because - (void)doJob:(MyObject*)parentThread is still in the same object (self is the same in both threads), self has nothing to do with your main thread its MyObject presumable, you also have a problem were you are not creating a new autorelease pool for your doJob:, doJob: should look like

- (void)doJob:(MyObject*)parentThread
{
    NSAutoreleasePool    * pool = [[NSAutoreleasePool alloc] init];
    ManipulatedObject *obj = [[ManipulatedObject alloc] init];
    obj.delegate = parentThread;
    [object startJob];
    [pool release];
}

you have to give us some information about how you're delegate method is being called, if it is tying to use timers or something like that then you are going to have problems because there is no runloop to add your timer to.

Nathan Day
  • 5,981
  • 2
  • 24
  • 40
  • Thanks for tips, but i'm not using timers. I only run the thread that i mentioned. – Misha Aug 09 '11 at 17:53
  • Well if you delegate setter is not being called but you code to create you ManipulatedObject instance is then the only thing I can think of is that [[ManipulatedObject alloc] init]; is falling and returning nil. – Nathan Day Aug 09 '11 at 18:05
  • ManipulatedObject is ok. However inside of it there is reverseGeocoder starts to run and it is the one who calls my callback method in main thread when there are results. Maybe there is a problem. – Misha Aug 09 '11 at 18:33