Delegate callback from other NSThread

2019-04-12 23:34发布

问题:

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];
}

回答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.



回答2:

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.