【问题标题】:Memory management using ARC on iOS在 iOS 上使用 ARC 进行内存管理
【发布时间】:2015-08-30 04:37:26
【问题描述】:

根据我刚刚解决的问题提出一个快速的问题(更多的是好奇心)(我将在帖子中发布我的问题的答案,可以在这里找到:My former question

问题是我有这个 UITableView 包含自定义单元格对象。每次进入此视图时,我都会为 UITableView 生成新的单元格,如下所示:

    if (cell == nil)
{
    [[NSBundle mainBundle] loadNibNamed:@"UploadCellView" owner:self options:nil];

    cell = customCell;
}

在标准方法中发生的情况:

-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath

现在的问题是我的自定义单元格对象侦听有关在后台发生的上传对象的 NSNotifications,因此它们可以将其模型数据更新为其标签和进度条等。它是这样发生的(这是自定义的方法单元格对象):

-(void) uploadProgress: (NSNotification*)notification
{
NSDictionary *userInfo = [notification userInfo];

NSNumber *uploadID = [userInfo valueForKey:@"uploadID"];

if (uploadID.integerValue == uploadActivity.uploadID)
{
    UIProgressView *theProgressBar = (UIProgressView*)[self viewWithTag:progressBarTag];

    [theProgressBar setProgress:(uploadActivity.percentageDone / 100) animated:YES];

    UILabel *statusText = (UILabel*)[self viewWithTag:percentageTag];

    [statusText setText:[NSString stringWithFormat:@"Uploader - %.f%% (%.01fMB ud af %.01fMB)", uploadActivity.percentageDone, uploadActivity.totalMBUploaded, uploadActivity.totalMBToUpload]];
}
}

上传完成后,他们只需执行以下操作:

-(void) uploadFinished: (NSNotification*)notification
{
NSDictionary *userInfo = [notification userInfo];

NSNumber *uploadID = [userInfo valueForKey:@"uploadID"];

if (uploadID.integerValue == uploadActivity.uploadID)
{        
    [self setUploadComplete];

    [[ApplicationActivities getSharedActivities] markUploadAsFinished:uploadActivity];

    NSLog(@"BEGINNING RELOAD");
    [parentTable reloadData];
    NSLog(@"ENDING RELOAD");
}
}

现在的问题是当他们调用自己的 tableview 时。当包含 tableview 的视图消失时,旧的自定义单元格对象在后台仍然存在,并获得 NSNotfications。当上传完成后,旧表格视图中的旧自定义单元格对象仍会尝试调用当时设置的 parentTable 属性,现在导致调用随机垃圾内存。

我解决这个问题的方法是在表格中创建一个包含所有单元格对象的数组,然后让它们在视图被关闭时停止侦听,如下所示:

-(void) viewWillDisappear:(BOOL)animated
{
    for (UploadCell *aCell in lol)
    {
        [aCell stopListening];
    }

    [self.navigationController popViewControllerAnimated:YES];
}

但这似乎有点像 hack。当视图被关闭时,我将如何确保自定义单元格对象被删除?因为当视图再次初始化时,无论如何都会简单地创建新单元格,所以我对旧单元格没有用处。

自定义视图单元格具有指向与之关联的 tableview 的强属性指针,但我认为 ARC 会确保 TableView 指针不会失效?显然它是某种方式。可能是因为弹出时包含的视图被删除了?

【问题讨论】:

    标签: ios pointers automatic-ref-counting instances


    【解决方案1】:

    听起来像单元格有一个指向 UITableViewDataSource 类的保留属性。

    它们应该有一个 assign 属性,然后在释放 table view 时它们将被正确释放(如果您的单元格保留它,则当前不能)。

    此外,当单元格从表格视图中删除时,应通过覆盖单元格didMoveToSuperview 方法来关闭通知:

    - (void)didMoveToSuperview
    {
        [super didMoveToSuperview];
        if ( [self superview] == nil )
        {
            [self unsubscribeFromYourNotifications];
        }
    }
    

    如果他们滚动屏幕,他们不会浪费资源更新内容。

    【讨论】:

    • 哈哈很有趣!我将单元格视图中的引用属性设置为要分配的 UITableView 视图,这解决了问题!现在我想知道的是,如果单元格视图保留了它们所指向的 UITableView 怎么会发生,以后再次调用它时会出现错误吗?我会从重新加载调用中得到很多奇怪的无法识别的选择器错误,就好像它们正在调用随机垃圾内存一样,无论那里发生了什么。如果他们有很强的留存率,那应该不会发生吗?
    • 他们不应该一直留在内存中,直到它的单元格被删除吗?另外,感谢有关 didMoveToSuperview 方法的提示 :) 不知道那个!
    • 我原以为这个类会像你说的那样留在内存中,不知道为什么它会产生所有无法识别的选择器,因为它认为它已被释放......除非那些来自其他部分已释放,就像表视图本身一样(即使表本身已释放,VC 可能仍然存在)
    • 我刚刚找到了为什么会这样的答案:) 可以在我的其他答案中找到答案:stackoverflow.com/questions/9337431/… 问题是即使 tablewiew 可能仍然存在数据源 itaelf geta 也会发布周围。
    • 啊哈,我以为你保留了数据源,而不是表格视图。
    【解决方案2】:

    您是否考虑过一个单独的更新模型,该模型在 uploadID 和侦听通知的单元之间保留一个映射?这样,单元格本身不负责更新表格,更新模型会这样做。当表消失时,您可以关闭更新模型。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-08
      • 2012-02-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多