【问题标题】:(iOS) NSMutableArray as property addObject does nothing(iOS) NSMutableArray 作为属性 addObject 什么都不做
【发布时间】:2012-02-20 06:51:27
【问题描述】:

我有一个UIViewController 的子类,其中NSMutableArray 作为属性用作UITableView 的数据源。我在情节提要中创建了该类的一个实例。

我想用addObject: 方法填充数组,但如果我尝试,数组总是返回(null)

我读到@synthesize 没有初始化数组,我可能需要覆盖-init 并在那里初始化NSMutableArray,但-init 永远不会被调用。

这应该如何工作?

【问题讨论】:

  • 具有NSMutableArray 属性的类是什么?它的超类是什么?您是在代码中还是在 nib 或情节提要中创建类实例?
  • 它是 UIViewController 的子类,链接到故事板视图。

标签: objective-c nsmutablearray


【解决方案1】:

您需要创建NSMutableArray 的实例并将其分配给属性。

由于具有该属性的对象是在情节提要中创建的UIViewController,因此您可以在几个不同的地方执行此操作。你可以覆盖initWithCoder:,或awakeFromNib,或viewDidLoad

如果您覆盖initWithCoder:,则必须调用super 方法。

如果您在 viewDidLoad 中执行此操作,则在加载视图之前不会创建数组,这不必立即发生。

我建议在awakeFromNib

@synthesize myArray = _myArray;

- (void)awakeFromNib {
    _myArray = [[NSMutableArray alloc] init];
}

另一种选择是通过覆盖属性的 getter 方法来懒惰地创建数组:

@synthesize myArray = _myArray;

- (NSMutableArray *)myArray {
    if (!_myArray)
        _myArray = [[NSMutableArray alloc] init];
    return _myArray;
}

如果您这样做,请务必始终使用 getter 方法(self.myArray[self myArray])访问数组,而不是直接访问实例变量(_myArray)。

【讨论】:

  • 谢谢 Rob,看起来 -awakeFromNib 是最好的地方,因为虽然调用了 -initWithCoder,但如果我实现它并执行if ([self = super] init]),我的协议方法都不会因为某种原因被调用。 init in -awakeFromNib 效果很好。
  • 附带说明,xcode 总是将 initWithNibName:bundle: 方法添加到我所有的 uiviewcontroller 子类中,但从未在其中任何一个子类中调用该方法。为什么它会在那里?移除它是否安全?
  • 如果您以编程方式创建视图控制器,则可以向该方法添加初始化代码。由于您在情节提要中创建视图控制器,因此可以删除虚拟方法。它只是 Xcode 用于 UIViewController 的新子类的标准模板的一部分。
【解决方案2】:

这是您的代码需要的:

@interface BlahBlah : UIViewController
@property (...) NSMutableArray *myArray;
@end

起初,*myArray 只是一个等于 nil 的指针。您还不能将其用作数组。它需要设置为有效的 NSMutableArray 实例。您需要在指定的初始化程序中执行此操作:

@implementation BlahBlah

@synthesize myArray;

// -initWithNibName:bundle: is the designated initializer for UIViewController
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle
{
    self = [super initWithNibName:nibName bundle:nibBundle];
    if (self) {
        myArray = [[NSMutableArray alloc] init];
        // now you can add objects to myArray
    }
    return self;
}

- (void)dealloc
{
    [myArray release];
    [super dealloc];
}

请注意,您不能只覆盖 -init;您必须为您的类覆盖指定的初始化程序。找出你正在实现的子类,找出它指定的初始化器是什么,覆盖它(但通常需要调用超类实现),然后初始化你的属性。

这里是Apple documentation regarding multiple/designated initializers

【讨论】:

  • 这是很常见的错误。记得初始化你的数组!
  • 它是 UIViewController 的子类(采用 UITableViewDelegate 和 UITableViewDataSource 协议)。 Xcode 没有在我的类实现中创建任何 init 方法。我尝试手动覆盖 -init 但它从未被调用。查看我项目中的其他一些 UITableView 子类,有些有 -initWithNibName:bundle: 所以我尝试复制该方法,但它也从未被调用。我应该在 UIViewController 子类中在哪里进行自定义初始化?
  • 从 UIViewController 文档中,指定的初始化程序是 - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle 。我在答案中更新了这个,但我没有测试过。
  • 我已经把它放在我的实现中:@implementation VideosTableViewController @synthesize myVideos; - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (self) { myVideos = [[NSMutableArray alloc] init]; } NSLog(@"init Called"); return self; } 但是'init called'从来没有命中日志。
  • 不幸的是,无论是否指定,iOS 在从 nib 加载对象时not调用initWithNibName:bundle:。它调用initWithCoder:
【解决方案3】:

@synthesis 也不分配。所以分配并初始化你的数组。那么它应该可以工作了。

【讨论】:

  • 在 viewDidLoad 中分配并初始化它
猜你喜欢
  • 2010-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-06-06
  • 1970-01-01
  • 2013-10-11
  • 1970-01-01
相关资源
最近更新 更多