1

I have a piece of ARC code written in Objective-C that is creating a block and will want to provide it to some Objective-C MRC code as a callback, to be called when an operation finishes. What is the safest way to do that? My hunch is to just provide the MRC code with a copy.

Is there a guide somewhere that explains the memory management issues that arise when mixing ARC and MRC code?

2
  • Post relevant code (as text) in your question. Commented Dec 23, 2022 at 3:41
  • The Dreams Wild covers the specific case you're describing, and the short answer is "follow the MRC rules and it will automatically interoperate." But to your question of the explicit docs, you want the Transitioning to ARC Release Notes which links to the other important MRC docs, and also Blocks Programming Topics Commented Dec 24, 2022 at 3:37

1 Answer 1

1

Provided you handle the request in-place, you don't need to do anything special under MRR, since blocks themselves make const copies of the referenced values. Thus in this example the callback parameter is retained automagically (and doesn't get released until after dispatch_after's block finishes):

- (void)calculateResult:(void (^)(NSInteger))callback {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4 * NSEC_PER_SEC)),
                   dispatch_get_main_queue(), ^{
        callback(_value);
    });
}

If you want to retain the callback and use it later on, then you should explicitly copy the block passed OR still copy it via synthesised properties with copy semantic:

NS_ASSUME_NONNULL_BEGIN

@interface TDWMrrObject ()

@property (copy, nonatomic, nullable) void(^callback)(NSInteger);
@property (assign, nonatomic, nullable) NSTimer *timer;
@property (assign, nonatomic) NSInteger value;

- (void)asyncCalculate;

@end

NS_ASSUME_NONNULL_END

@implementation TDWMrrObject

#pragma mark Lifecycle

- (instancetype)init {
    if (self = [super init]) {
        _value = 4;
    }
    return self;
}

- (void)dealloc {
    [_callback release];
    [_timer invalidate];
    [super dealloc];
}

#pragma mark Actions

- (void)calculateResult:(void (^)(NSInteger))callback {
    self.callback = callback;
    [self asyncCalculate];
}

#pragma mark Private

- (void)asyncCalculate {
    if (_timer) {
        [_timer invalidate];
    }

    self.timer = [NSTimer scheduledTimerWithTimeInterval:4 repeats:NO block:^(NSTimer * _Nonnull timer) {
        _callback(_value);
        self.callback = nil;
        self.timer = nil;
    }];
}

@end
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.