1

I'm pretty sure this is 100% safe, but I don't want to miss anything. I have the following code

- (void) scheduleControlSurfaceProcess {
    [self.operationQueueForMessageProcessing addOperationWithBlock:^{
        // do something
        [self scheduleControlSurfaceProcess];     
    }];
}

where self is a Singleton. The block works splendidly as a non-main-thread thread. I do not see any memory problems in the profiler (which I don't trust much).

So, may I ignore the warning, "Block will be retained by an object strongly retained by the captured object?" If not, how can I insist that the block to get released (with ARC)? Getting the warning to go away is easy enough, but assigning id what = self seems like it would not solve the problem.

EDIT: as I realized quite late in this question, the real problem here was that I am rescheduling from within the block itself. This is obviously problematic, because each block retains the next.

NOTE: I am aware that there are lots of questions on this topic, but I'm not expert enough to know which, if any, situations are similar to this one.

Community
  • 1
  • 1
Dan Rosenstark
  • 68,471
  • 58
  • 283
  • 421

1 Answers1

5
- (void) scheduleControlSurfaceProcess {
    __weak id SELF = self;
    [self.operationQueueForMessageProcessing addOperationWithBlock:^{
        id strongSelf = SELF; //Guarantee self doesn't go away in the meantime
        // do something
        [self.operationQueueForMessageProcessing addOperationWithBlock:^{
            [strongSelf scheduleControlSurfaceProcess]; 
        }];
    }];
}

That would guarantee you won't have a cycle here. The warning is completely valid, self retains the operation queue, the queue retains the block, the block retains self. And round and round we go.

In my modified example the block will capture SELF and store it into 'strongSelf'. The strongSelf step isn't strictly necessary, but it will make sure the reference to self doesn't get niled during execution of the block.

Joshua Weinberg
  • 28,598
  • 2
  • 97
  • 90
  • +1 thanks. I'm really surprised but it WOULD explain some recent crashes with NO crash log. BTW am I the ONLY dev who is still building for 4.3, and if so, is that daft for an app that will come out in January? Anyway, if 4.x must use `__unsafe_unretained`, I think. My understanding is that 50% of iPad users or more still use 4.x. – Dan Rosenstark Dec 27 '11 at 16:22
  • 1
    For all new development I would suggest 5.0+. It just isn't worth the effort to support 4.x anymore. But yes, replace __weak with __unsafe_unretained in that case. – Joshua Weinberg Dec 27 '11 at 16:25
  • Now I'm really confused. I am definitely leaking my blocks still, after adjusting as you suggested. What are the rules for the `scheduleControlSurfaceProcess` method called from within the block? Xcode surely isn't parsing it for this. Thanks in advance for any help. – Dan Rosenstark Dec 27 '11 at 20:09
  • without more info I can't tell you what would be going on. – Joshua Weinberg Dec 27 '11 at 20:14
  • Sorry, situation is utterly stupid, I think. As in the question, the operation calls itself, which is mad. – Dan Rosenstark Dec 27 '11 at 21:20
  • 1
    Oh, wow, I didn't even notice that. Added some code that should fix that for you. – Joshua Weinberg Dec 27 '11 at 21:22
  • Awesome, thanks so much. Is there any way to dispatch on the same Queue I was on (strongSelf. operationQueueForMessageProcessing)? – Dan Rosenstark Dec 27 '11 at 21:35
  • Sorry to bother ya, but the new code would schedule TWICE. Perhaps my original code was okay? I think it definitely caused a huge memory leak. – Dan Rosenstark Dec 28 '11 at 01:30
  • And then you use self.operationQueueForMessageProcessing inside of the block after all these tricks with weak/strong couple. – pronebird Aug 29 '13 at 17:38
  • So, what if this block will execute, when self nil already? Is it any way that to assure, that self not nilled before execution of block? – skywinder Jan 26 '14 at 23:44