ARC 和指针存储

ARC and pointer storing

提问人:Arainty 提问时间:2/28/2021 更新时间:3/6/2021 访问量:113

问:

我的情况比我在发帖之前看到的要复杂一些,而且我不太擅长内存管理。

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

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
}

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

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

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

谢谢!

编辑:忘了提到我使用

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

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

ios objective-c 内存管理 自动引用计数

评论

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

答:

1赞 Rob 2/28/2021 #1

几点:

  1. 该模式有一个非常具体的用途,即被调用方法创建一个对象,并且需要更新调用方的指针来引用这个新对象。例如,考虑正则表达式文档中的示例:* __autoreleasing *

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

    所以,是一个指针,调用方是 向该指针提供地址,以便在实例化对象时,它可以更新调用方的引用以指向该指针。errorNSErrorregularExpressionWithPatternNSError

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

  2. 你说:

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

    这种逻辑并不完全正确。 是指向该的指针 原始对象,而不是它的副本。您可以在没有 求助于“指针到指针”模式。就您而言,如果 你只会使用 ,而不是 .MyCell *MyCell *MyCell * *

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

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

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


因此,我建议使用指向模型对象的简单指针(而不是指向指针的指针):

@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];

有关向视图控制器传递数据和从视图控制器传递数据的信息,请参阅在视图控制器之间传递数据。但是,作为一般规则,一个视图控制器不应访问另一个视图控制器的视图对象。

评论

0赞 Arainty 2/28/2021
谢谢!我理解你的观点和 objc 惯例。我这样做是因为我不想为每个自定义视图创建一个模型,因为我做了很多模型。此外,您的解决方案将不起作用,因为我想从中调用方法,而如果没有指针引用,我就不能......我还有其他属性,这就是为什么我传递了单元格本身,以使用其属性并能够从中调用方法。MyCellMyCell
0赞 Arainty 2/28/2021
我要调用的单元格的方法会进行一些处理并设置单元格标签的文本,这就是我需要调用它的原因
0赞 Rob 2/28/2021
视图既不用于存储模型数据,也不用于处理该数据。但我明白了,你现在不想处理更广泛的架构设计。理解,祝你好运