【问题标题】:ARC and pointer storingARC和指针存储
【发布时间】:2021-05-29 21:10:56
【问题描述】:

我的情况比我在发帖前在这里看到的要复杂一些,而且我对内存管理不是很擅长。

我有一个自定义的UITableViewCell(我们将在此处称为MyCell)并在单击它时将其指针传递给UITableViewController(此处为MyController)。我传递了 指针 因为我想调用这个单元格的方法,并且引用只能通过 Objective-C 中的复制进行,因此它不会调用右侧单元格上的方法。我做了这个:

MyController.h

@interface MyController : UITableViewController {
    MyCell * __autoreleasing *_cell;
}
-(instancetype)initWithCell:(MyCell * __autoreleasing *)cell;
@end

MyController.m

- (instancetype)initWithCell:(MyCell **)cell {
    if (self = [super init]) {
        _cell = cell;
        // Checkpoint 1
    }
}

然后我想稍后在我的代码中使用这个变量,例如定义部分的数量:

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    // Checkpoint 2
    return (*_cell).contents.count; // contents being an NSArray property of the custom cell
}

问题:在此处标记的“检查点”处,我有一个 NSLog(@"%ld", (unsigned long)(*_cell).contents.count);,但它在第一个检查点显示 2(正确的数字),但在第二个检查点显示 0检查点,所以基本上当我单击单元格时,会显示一个空表视图。

我曾经通过将单元格存储在nonatomic, strong 属性中来通过副本传递单元格,并且一切正常,但是由于指针引用,通过将调用从self.cell 更改为_cell,视图现在为空我说。这可能是一个内存管理问题,但我不知道如何解决它(Objective-C 相当新,第一个应用程序)。

注意:我尝试将__autoreleasing 更改为__strong,但这会导致每次访问_cell 的属性时都会崩溃。我也尝试使用 nonatomic, assign 属性来存储它而不是使用 ivar,但它并没有解决我的问题。

谢谢!

编辑:忘了说我是通过使用来调用视图控制器的

[self.navigationController pushViewController:[[MyController alloc] initWithCell:(MyCell **)&cell] animated:YES];

在我之前的视图控制器中,在tableView:didSelectRowAtIndexPath: 方法中。

【问题讨论】:

  • 那么我如何从它推送的MyController 更新“调用者”单元格MyCell
  • 您的链接非常全面,谢谢。我可能会做一个代表。您能否简要解释一下我应该如何重构我的代码?
  • 1.不要使用单元格来存储模型数据。如果你想为它提供模型数据以便它可以自行配置,很好,但它不是用于存储,而只是用于显示和捕获。 2. 如果您有“处理”代码,也应该将其从单元格中提取出来。 3. 将数据从呈现视图控制器传回呈现视图控制器的委托协议模式。
  • 非常感谢,会做的!谢谢你给我的时间。

标签: ios objective-c memory-management automatic-ref-counting


【解决方案1】:

几点:

  1. * __autoreleasing * 模式有一个非常特殊的用途,即被调用的方法创建一个对象并需要更新调用者的指针以引用这个新对象。例如,考虑正则表达式documentation中的一个示例:

    NSError *error = NULL;
    NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"\\b(a|b)(c|d)\\b"
                                                                           options:NSRegularExpressionCaseInsensitive
                                                                             error:&error];
    

    所以,error 是一个 NSError 指针,调用者是 为该指针提供地址,这样如果 regularExpressionWithPattern 实例化一个 NSError 对象,它可以更新调用者的引用指向它。

    您唯一需要使用这种“指向指针”模式的时间 是当被调用的例程正在实例化一个对象并想要 更新调用例程的指针。我们一般只需要 当您想要返回多个指针时使用该模式 对象(例如,在 regularExpressionWithPattern 的情况下,它将 返回一个NSRegularExpression * 指针,但也可以选择 也想更新NSError * 指针)。

  2. 你说:

    我传递指针是因为我想调用这个单元格的一个方法,并且引用只能通过 Objective-C 中的复制进行,所以它不会调用右侧单元格上的方法。

    这个逻辑不太对。 MyCell * 是指向它的指针 原始对象,而不是它的副本。你可以在没有的情况下访问它 诉诸“指针指向指针”模式。在你的情况下,如果 你只会使用MyCell *,而不是MyCell * *

  3. 您根本不应该将单元格引用传递给此视图控制器...一个视图控制器不应该进入另一个视图控制器的视图层次结构;

  4. 表格视图具有与单元格重用相关的各种优化...除了在其自己的表格视图数据源和委托方法中进行交互之外,不应使用单元格;和

  5. 不应使用单元格(“视图”对象)来存储“模型”数据(当前存储在 contents 属性中的数据)。不要将“模型”(数据)与“视图”(UI)混为一谈。


所以,我建议一个指向模型对象的简单指针(不是指向指针的指针):

@interface MyController : UITableViewController
@property (nonatomic, strong) NSArray <ModelObject *> *contents; // or whatever you previously stored in cell `contents`
@end

然后:

MyController *controller = [[MyController alloc] init]; // usually we'd instantiate it using a storyboard reference, but I'm gather you're building your view hierarchy manually
controller.contents = self.contents[indexPath.row]; // note, not `cell.contents`, but rather refer to this current view controller’s model, not the cell (the “view”)
[self.navigationController pushViewController:controller animated:YES];

关于将数据传入和传出视图控制器,请参阅Passing data between view controllers。但是,作为一般规则,一个视图控制器不应该访问另一个视图对象。

【讨论】:

  • 谢谢!我理解你的观点和 objc 约定。我这样做是因为我不想为每个自定义视图创建一个模型,因为我做了很多。您的解决方案也不起作用,因为我想从 MyCell 调用一个方法,而我不能没有指针引用...我在 MyCell 中还有其他属性,这就是我传递单元格本身的原因,以使用它的属性加上能够从中调用方法。
  • 我要调用的单元格的方法会进行一些处理并设置单元格标签的文本,这就是我需要调用它的原因
  • 视图既不用于存储模型数据,也不用于处理该数据。但我明白了,你现在不想处理更广泛的架构设计。理解并祝你好运
猜你喜欢
  • 1970-01-01
  • 2011-07-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多