viewDidLoad 在 ARC 中过早释放?

viewDidLoad deallocated prematurely in ARC?

我正在编写一个具有 NSOutlineView 的应用程序和一个实现 NSOutlineViewDataSource 的接口。但是,在运行时,应用程序崩溃并出现错误消息已发送到已释放的实例。我用 zombies 和 Instruments 做了一些调试,我找到了被释放的地址。

我不太明白这是怎么回事。我已经确定,如果我为 ViewController.m 禁用 ARC,它不会出现段错误。这是相关代码。

-(void)viewDidLoad {
    [super viewDidLoad];
    NSArray * array = [[NSArray alloc]initWithObjects:@"chrisdotcode",@"Mop",@"ollien", nil];
    [self.namesList setDataSource:[[ArrayOutlineDataSource alloc] init:array]];
}

这里是实现 NSOutlineViewDataSource 的 ArrayOutlineDataSource。

@implementation ArrayOutlineDataSource
    -(id)init:(NSArray *)array{
        self.array = array;
        return [super init];
    }
    -(id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item{
        return self.array[index];
    }
    -(BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item{
        return false;
    }
    -(NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item{
        NSLog(@"Item:%@",item);
        NSLog(@"Item count:%lu",(unsigned long)[self.array count]);
        return [self.array count];
    }
    -(id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item{
        return self.array;
    }



@end

documentation 说:

An outline view does not own its data source. Similarly, it does not own the objects it gets from the data source—if they are released your application is likely to crash unless you tell the outline view to reload its data.

The data source is a controller object, and you are responsible for ensuring that it is not deallocated before the outline view is finished with it (typically the data source is an object such as the document object in a document-based application, so there is no additional work to do). The data source is in turn responsible for retaining all of the objects it provides to an outline view, and updating the outline view when there’s a change to the model. It is therefore not safe to release the root item—or any children—until you’re no longer displaying it in the outline view.

最重要的是,大纲视图不维护对其数据源的强引用。 (这很常见:通常数据源和委托是弱引用。)问题中的代码示例未保留 ArrayOutlineDataSource.

创建您自己的 属性 以保持对此 ArrayOutlineDataSource:

的强引用
@property (nonatomic, strong) ArrayOutlineDataSource *dataSource;

然后:

- (void)viewDidLoad {
    [super viewDidLoad];
    NSArray * array = [[NSArray alloc]initWithObjects:@"chrisdotcode",@"Mop",@"ollien", nil];
    self.dataSource = [[ArrayOutlineDataSource alloc] init:array];
    [self.namesList setDataSource:self.dataSource];
}