You cannot dereference ivars with -> if this is nil. So, the typical solution is to create strong reference that can’t be deallocated while the closure runs, and return if it’s nil:
- (NSString * _Nullable)process {
    typeof(self) __weak weakSelf = self;
    [self asynchronousMethodWithCompletion:^{
        typeof(self) strongSelf = weakSelf;
        if (!strongSelf) { return; }
        // can now safely use `strongSelf` here
    });
    ...
}
This is “weakSelf-strongSelf dance”. You use it in situations where you need to make sure that self isn’t nil when you use it, e.g. dereferencing ivars (strongSelf->ivar) .
Thus:
- (NSString * _Nullable)process {
    typeof(self) __weak weakSelf = self;
    NSString __block *ret = nil;
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_enter(group);
    dispatch_async(_repQueue, ^{
        typeof(self) strongSelf = weakSelf;
        if (!strongSelf) { return; }
        [strongSelf updateFromTable:[strongSelf->_env table] env:strongSelf->_env callback:^{
            ret = [some op .. ];
            dispatch_group_leave(group);
        }];
    });
    dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
    info(@"%@", @"done");
    return ret;
}
A few other observations:
- The dispatch group should be a local variable of the method rather than an ivar. There’s no need for anything else in your code referencing this - group.
 
- Make sure that your - dispatch_group_leavecalls don’t exceed the number of- dispatch_group_entercalls (i.e. that this completion handler block isn’t called multiple times).
 
- I’d suggest waiting for - DISPATCH_TIME_FOREVER(assuming you want it to really wait for it to finish).
 
- Also, if these are properties (which I’m guessing they are on the basis of the underscores), then using - self.envrather than- self->_envis safer, as it won’t crash if- selfis- nil, but rather will just return- nil.
 
I must confess that this still doesn’t look right (e.g. if updateFromTable is asynchronous already, why bother dispatching this asynchronously to _repQueue; if it is synchronous, then again, why dispatch this asynchronously only to wait for it). But it’s impossible to comment further without seeing the updateFromTable implementation.
Or, better, make the method asynchronous:
- (void)processWithCompletion:(void (^)(NSString *))callback {
    typeof(self) __weak weakSelf = self;
    dispatch_async(_repQueue, ^{
        typeof(self) strongSelf = weakSelf;
        if (!strongSelf) { return; }
        [strongSelf updateFromTable:[strongSelf->_env table] env:strongSelf->_env callback:^{
            NSString *ret = [some op .. ];
            callback(ret);
        }];
    });
}