简体   繁体   中英

UITableViewCell not released when reloaded

Optimising my code after moving to ARC I am running into the following issue:

I have a UITableView with two cells: DOArticleHeaderCell and DOArticleContentCell . The content cell has DOWebView , which is a UIWebview with a function to do a callback when loaded so the cell can be reloaded and the height adjusted.

DOWebView.h:

@interface DOWebView : UIWebView <UIWebViewDelegate> {
    bool _reload;
    __weak id <DOWebViewCallback> _callback;
}

@property (weak, nonatomic) id <DOWebViewCallback> callback;

- (void) loadHTMLString:(NSString*) text baseURL:(NSURL*) url;
- (void) updateWebview;
- (void) stopWebview;

@end

DOWebView.m

- (void)webViewDidFinishLoad:(UIWebView *)aWebView
{
    if([super respondsToSelector:@selector(scrollView)]) {
        super.scrollView.scrollEnabled = false;
    }

    id appDelegate = (iDomsAppDelegate *)[[UIApplication sharedApplication] delegate];

    // finished loading, hide the activity indicator in the status bar
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    DOSetting *zoomLevel = (DOSetting *)[[appDelegate dataManager] findSetting:@"zoomLevel"];

    [super stringByEvaluatingJavaScriptFromString:[NSString stringWithFormat:@"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust= '%@%%'", zoomLevel.value]];

    if(![zoomLevel.value isEqualToString:@"100"]){
        // Allows the web view to update itself with new scroll 
        [self performSelector:@selector(correctSize) withObject:nil afterDelay:1];
    } else {
        [self correctSize];
    }

}

- (void) correctSize {
    CGSize fittingSize = [super sizeThatFits:CGSizeZero];
    if((fittingSize.height > [super frame].size.height) || ([super frame].size.height - fittingSize.height > 50)){
        if([super delegate] == nil) {
            return;
        }
        [self stopWebview];
        if(_reload || fittingSize.height - [super frame].size.height > 50){
            [_callback setContentSizeAndReloadData:fittingSize.height reloadAnyway:true];
        } else {
            [_callback setContentSizeAndReloadData:fittingSize.height reloadAnyway:false];
        }
    }
    _reload = false;
}

This calls upon the following:

@interface DOArticleContentCell : DOPrototypeCell <DOWebViewCallback> {
    @private
    __weak IBOutlet DOWebView* _webView;
    __weak IBOutlet UIButton* _websiteBttn;
    __weak IBOutlet UIButton* _shareBttn;
    __weak IBOutlet UIButton* _fullscreenBttn;

    __weak IBOutlet UIButton* _increaseFontSizeBttn;
    __weak IBOutlet UIButton* _decreateFontSizeBttn;
    __weak IBOutlet UIButton* _resetFontSizeBttn;

    //bool _reload;
    __weak DOArticle* _article;
    //__weak DOSocialMediaHelper* _socialMediaHelper;
}

@property (nonatomic, weak) DOArticle *article;
@property (nonatomic, weak) DOWebView* webView;
@property (weak, nonatomic) id <DOArticleViewControllerDelegate> delegate;

- (IBAction)showActionSheet:(id)sender;
- (IBAction)increaseFontSize:(id)sender;
- (IBAction)decreaseFontSize:(id)sender;
- (IBAction)openWebsite:(id)sender;
- (void) populateCellSimple:(NSString *) htmlText;

@end

With the callback function, which call the tableView:

- (void) setContentSizeAndReloadData:(int)size reloadAnyway:(bool)reload {
    //__weak DOArticleContentCell *weakLink = self;

    __weak id weakSelf = self;
    [delegate setContentSizeAndReloadData:weakSelf size:size reloadAnyway:reload];
}

DOArticleViewController.h:

@interface DOArticleViewController : DOPrototypeViewController <DOArticleViewControllerDelegate> {
    DOArticle* _article; 
    int _fittingSize;
    bool _didReloadContentRow;
    bool _notification;  
    bool _multiLanguages;

    __weak IBOutlet UITableView * _tableView;
    IBOutlet DOAudioControllerCell* _audioCell;    
}

- (IBAction)fullScreen:(id)sender;
- (void) reloadArticle:(DOArticle*) article;
- (void) unLoad;

@property (nonatomic, strong) DOArticle *article;
@property (nonatomic) bool *notification;
@property (nonatomic, weak) UITableView *tableView;


@end

In DOArticleViewController.m:

#pragma mark - Delegate
- (void) setContentSizeAndReloadData:(DOArticleContentCell *) cell size:(int) size reloadAnyway:(bool)reload {

    _fittingSize = size;

    // For now only do when not set. Otherwise there is an issue with a wider frame, as there would be a lot of white under it and no known way at present to detect this without creating a smaller fraome first and to reload.
    if([_article.estimatedHeight intValue] <= 0){
       // NSLog(@"Updating article height and saved! (%i vs %i)", [_article.estimatedHeight intValue], size);
        _article.estimatedHeight = [NSNumber numberWithInt:size];

        id appDelegate = (iDomsAppDelegate *)[[UIApplication sharedApplication] delegate];
        [[appDelegate dataManager] commitChanges];
    }

    if(!_didReloadContentRow || reload){
        NSIndexPath *indexPath = [_tableView indexPathForCell:cell];

        // Remove the delagate incase it relaods
        [[cell webView] stopWebview];

        [_tableView beginUpdates];
        [_tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        [_tableView endUpdates];

    }

    _didReloadContentRow = true;
}

If I take [_tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade]; out, the releasing works fine, but if it is in both the DOArticleHeaderCell and DOArticleContentCell stay active in memory after the parent releases.

I think this specific problem might have been due to the use of the simulator, as it doesn't appear when running the same test on a device. I am not 100% sure but it seems that way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM