smartdevicelink / sdl_ios

Get your app connected to the 🚙, make your users feel like a 🌟
www.smartdevicelink.com
BSD 3-Clause "New" or "Revised" License
169 stars 105 forks source link

Audit blocks' implicit 'self' capturing #129

Closed joeljfischer closed 9 years ago

joeljfischer commented 9 years ago

Accessing iVars within blocks causes an implicit capture of self, which will lead to a retain cycle. The library needs to be audited for these issues. Below is one such:

-(void) append:(id) toAppend {
    dispatch_async(dispatch_get_main_queue(), ^{
        //Insert the new data
        NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];

        [dictionary setObject:toAppend forKey:@"object"];
        [dictionary setObject:[NSDate date] forKey:@"date"];

        [messageList addObject:dictionary];
        NSIndexPath *newIndex = [NSIndexPath indexPathForRow:(messageList.count - 1) inSection:0];
        [self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:newIndex] withRowAnimation:UITableViewRowAnimationBottom];

        //If we were at the bottom, scroll to the new bottom.
        if (atBottom) {
            [self.tableView scrollToRowAtIndexPath:newIndex atScrollPosition:UITableViewScrollPositionBottom animated:YES];
        }

        [self.tableView reloadData];
    });
}

(Note this is a bad example, since self doesn't actually capture this block)

Here, both messageList and atBottom are iVars, which means that their calls actually look like self->messageList. This is an implicit capture of self and a retain cycle. One way to resolve this is to create a "weak" self outside of the block using something like __weak typeof(self) weakSelf = self, then within the block, recapturing the weakSelf as a strong, but scoped variable that will be released at the end of the block.

Simply using the weakSelf could mean that it is released out from under us in the middle of the block. So within the block we would have __strong typeof(self) strongSelf = weakSelf. Then to access the iVars, properties, call methods, etc. we would reference the strongSelf, like so: [strongSelf->messageList addObject:dictionary].

adein commented 9 years ago

@joeljfischer I think this SO post is related to what you were describing: Strong To Weak Reference

joeljfischer commented 9 years ago

Yup, that describes it. It's also described in WWDC 2012 Session 712. This links to the PDF which you can only see logged in to Apple's dev site. See page 105.

joeljfischer commented 9 years ago

Fixed in #316