How to retain the object which runs async task in another object and get the async task run successfully?

129 views Asked by At
  • I have two objects of each ClassA and ClassB respectively.
  • ClassB contains a method which is big which I want to run async in the background or say other async thread.
  • I have object of ClassA retained properly, however, I have a property of object of ClassB in object of ClassA. This helps me to keep the object of ClassB retained till its async method finishes.
  • Issue : When I run the following code on mainThread it runs ok, but when I put the long running method in async thread then objectB gets deallocated instantly and nothing happens.

     @interface ClassA : NSObject
    
     @property(nonatomic, strong) ClassB *objB;
    
     @implementation ClassA
    
     -(void)createAndExecuteB
     {
         self.objB = [ClassB getNewAndExecute];
     }
    
    
     @interface ClassB
    
     +(ClassB *)getNewAndExecute;
    
     @end
    
     @implementation ClassB
    
     -(void)timeConsumingTask
     {
        //statements
     }
    
    +(ClassB *)getNewAndExecute
    {
         ClassB * __block objB = [[ClassB alloc] init];
    
       //Here is my issue. If I remove this dispatch code and just call
       // the timeConsumingTask method, then everything works well (blocking
       // the UI thread for a while but completing the tasks properly).
       // but if I keep the dispatch code, then this object gets instantly
       // deallocated and nothing runs
            dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0) ,^{
              [objB timeConsumingTask];
     });
    
     return objB;
     }
      @end
    
1

There are 1 answers

3
Ewan Mellor On

This code should be working fine, so the problem must be somewhere that you're not showing us.

You could be

  1. calling [ClassB getNewAndExecute] directly rather than through [classA createAndExecuteB];
  2. not retaining the A instance for the full duration of the task like you think you are;
  3. calling [classA createAndExecuteB] multiple times on the same ClassA instance, which would overwrite the self.classB that you're trying to retain.

It is notable that you don't show what happens at the end of timeConsumingTask. How does ClassA or whatever is retaining ClassA know that timeConsumingTask is complete? That's the time that you have to release the ClassB instance so it's important.

Checking 1 should be easy.

To check 2, add a dealloc method to ClassA and ClassB and add NSLog statements or set breakpoints on them so that you can see when your objects are being deallocated.

To check 3, add an NSLog to createAndExecuteB so that you can see how many calls you're getting.

This is a good trick, printing the pointers of the objects so that you can see whether you're re-using instances by accident:

NSLog(@"%p %p", (void *)self, (void *)self.classB);