objective-cgrand-central-dispatchretain-cyclestrong-reference-cycle

if self in dispatch_source_set_event_handler need to be weak


I got a timer for uploading logs,here is the code:

- (void)setupTimer {
    if (_timerForRecording) {
        dispatch_source_cancel(_timerForRecording);
        _timerForRecording = NULL;
    }
    
    _timerForRecording = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, _safeTransactionQueue);
    if (_timerForRecording) {
        dispatch_source_set_timer(_timerForRecording, dispatch_time(DISPATCH_TIME_NOW, 4.5 * NSEC_PER_SEC), 4.5 * NSEC_PER_SEC, 0.5 * NSEC_PER_SEC);
        dispatch_source_set_event_handler(_timerForRecording, ^{
            [self sendLog];
        });
        dispatch_resume(_timerForRecording);
    }
}

seems like using self won't cause retain cycle, should I use weakSelf instead?


Solution

  • tl;dr

    Yes, you have introduced a strong reference cycle. You should use weakSelf pattern.


    Needless to say, in the case of a timer, you could just add some logging in the timer code, so you will see that the timer is still firing after its owner has been dismissed.

    But more generally, to identify whether objects remain in memory longer than intended, one can empirically verify this with the “Debug Memory Graph” feature.

    E.g., here I started the timer in a view controller, presented and dismissed this view controller three times, and the panel to the left of my memory graph shows that I have three instances of that view controller still in memory!

    enter image description here

    Sometimes, we will be lucky enough that the “memory graph” will successfully identify this as a strong reference cycle (and you may see ⚠️ warning icons or circular graphs in the main panel). But, sometimes, such as in this case, you will just see the lingering instances, at which point you can start your hunt for the strong reference cycle (which you have successfully already identified here).

    In this case, I:

    enter image description here

    Once I defined weakSelf and modified the block to call [weakSelf sendLog], I repeated the above steps. There were no more lingering objects. I then removed the “Malloc stack” diagnostics once I confirmed there were no more strong reference cycles.