【问题标题】:Is it bad to set up a property in the getter method?在 getter 方法中设置属性是不是很糟糕?
【发布时间】:2012-05-28 22:16:31
【问题描述】:

如果我有一个属性,比如一个 NSArray,它只会为我的类的每个实例初始化一次,这有什么问题吗:

(在界面中)

@property(strong, nonatomic)NSArray *bubbleArr;

(在实现中)

-(NSArray*)bubbleArr
{
    if(!bubbleArr)
    {
        NSMutableArray *tempBubbArr = [[NSMutableArray alloc] init];
        // get filepath for first speech bubble image for page
        NSString *speechBubbleImgPath = [[NSBundle mainBundle] pathForResource:
                                         [NSString stringWithFormat:@"speech_%i_0", pageIndex]
                                                                        ofType:@"png"];

        for(int i = 1; speechBubbleImgPath; i++)
        {
            UIImage *speechBubbleImg = [[UIImage alloc] initWithContentsOfFile:speechBubbleImgPath];
            UIImageView *speechBubbleImgView = [[UIImageView alloc] initWithImage:speechBubbleImg];

            [tempBubbArr addObject:speechBubbleImgView];

            speechBubbleImg = nil;
            speechBubbleImgView = nil;
            speechBubbleImgPath = nil;

            speechBubbleImgPath = [[NSBundle mainBundle] pathForResource:
                                   [NSString stringWithFormat:@"speech_%i_%i", pageIndex, i]
                                                                  ofType:@"png"];
        }

        bubbleArr = [[NSArray alloc] initWithArray:tempBubbArr];

        tempBubbArr = nil;
    }

    return bubbleArr;
}

我从未使用过自定义访问器方法,但这似乎是一种干净的设置方式,因此我不必在viewDidLoad 或其他地方设置每个属性,也不必担心关于它是nil。我不记得曾经真正遇到过这样做的代码。这是推荐的方法吗?另外,我总是想使用self.bubbleArr 来确保调用此方法,对吗?

【问题讨论】:

  • 旁注:请注意,如果您不使用 ARC,则上面的代码会泄漏
  • 查看代码,我猜您不希望更改数组引用,因为它是一次性设置。您可以考虑将其设为 readonly 属性以确保这一点。否则代码如object. bubbleArr = [[NSArray alloc] init];可能会把事情搞砸。
  • 在 getter 中使用惰性初始化技术绝对没有错。但是,对于非只读属性,您需要确保 setter 适当地了解事情的工作方式,并且如果异步访问(多线程)是可能的,您需要在 getter 和 setter 中考虑到这一点。 (我没有尝试分析/批评您的实施。)
  • 啊好吧我想知道我是否应该让它只读。谢谢!

标签: objective-c ios getter accessor


【解决方案1】:

这是设置您的财产的一种完全有效的方式。 Apple 在他们的示例代码以及他们的项目模板中经常做这种事情。例如,查看新创建的核心数据 iOS 项目中的核心数据堆栈设置。正如@WendiKidd 所指出的,您必须始终通过访问器访问您的变量,以确保它正常工作(这可能是您应该做的)。

特别是,这是实现类属性的好方法,该属性实际上只能返回一件事(从您的评论来看,这听起来像是您正在尝试做的事情)。如果这是您的目标,请遵循以下准则:

  1. 将您的财产声明为readonly
  2. 如果它应该是可公开访问的,则在公共标头中声明它,如果它应该是“私有”,则在 .m 文件的类扩展中声明
  3. 如果它可以/应该由变量支持,则合成 ivar 并按照您所做的那样覆盖 getter
  4. 如果它不应该/不必由变量支持,请在实现中将属性声明为 @dynamic 并覆盖 getter
  5. 只能通过访问器访问您的 ivar

在第 4 点将变量声明为动态变量将向查看您的代码的任何人发出信号,表明您可能已经为该属性编写了自定义访问器。

【讨论】:

  • @bbum -- 非常正确。我这样做是为了提醒自己,我在没有合成 ivar 的情况下覆盖了访问器。我想这真的是个人品味的问题......
  • 我认为第 1 点并不是那么有效,因为在没有专门配置和分配默认对象时加载默认对象通常很方便。
  • @Paul.s -- 我同意,但 OP 在 cmets 中对 WendiKidd 的回答写道:“我几乎想要一个‘常量数组’效果,因为它可以/应该只是一个特定的每个实例的数组”这是这个答案所要解决的问题,也是我在我的观点之前的段落中解释的内容
  • 附带说明...使用 ARC,我通常在viewDidUnload 中将我的属性设置为nil。但是,readonly 不允许我这样做。你如何确保内存被释放?
  • 使用ARC,内存将在-dealloc方法中被释放,实例变量将直接发送-release消息。 ARC 为您处理这一切,因此您无需自己实现 -dealloc
【解决方案2】:

等到需要变量的内容来初始化它的技术称为“延迟加载”,是一种有效的技术。不过,我不确定是否要在 getter 中执行此操作。

我认为你的帖子的最后一行准确地描述了这个问题——是的,当你想要引用对象时,你总是必须确保调用 getter 方法,即使在类本身内部也是如此。很容易犯错误并且不能正确地做到这一点,如果您的代码将来可以传递给另一个开发人员,这是一个特别糟糕的主意。他们绝对不会期望您以这种方式进行设置,并且当他们期望能够正常访问变量时可能会遇到问题。在 viewDidLoad 中初始化成员变量是一种常见且公认的做法。

所以是的——这在技术上是可行的,尽管从设计角度来说不是一个非常合理的设置。我强烈反对它。但如果你只是想知道它是否会起作用,答案是肯定的。

【讨论】:

  • 我也不知道它们是否保证初始化为零,但我从未见过不会发生这种情况的情况。
  • stackoverflow.com/questions/990817 - 此外,这很常见,任何未来的维护者都应该注意这个习语。将实例变量命名为_bubbleArr 也很常见,以防止意外直接引用实例变量。
  • @IanHenry 好奇心得到了解答!谢谢!很高兴知道:)
  • 我认为这是一种有效的技术(我不确定这个具体的例子,因为我没有研究它的副作用等)。将此代码转储到viewDidLoad 并没有多大意义,因为当视图加载时您可能没有使用它。无论如何,通过属性来获得良好的封装和更灵活且易于更改代码通常总是一个好主意。
  • 这实际上是objective-c中一个非常标准的设计,所以如果你的代码被提供给花了一些时间编写语言的其他人,他们应该会发现这是一种完全正常的方式做事。
【解决方案3】:

是的,如果您不使用 self.bubbleArray 或 [self bubbleArray],您将不会调用该方法。

除此之外,这完全是管理属性实例化的好方法。

【讨论】:

    【解决方案4】:

    这似乎是一个干净的解决方案,感觉有点像延迟加载。但我不确定我会这样做。

    【讨论】:

      猜你喜欢
      • 2012-01-11
      • 1970-01-01
      • 1970-01-01
      • 2013-03-28
      • 2011-09-20
      • 2018-01-20
      • 2011-10-06
      • 2020-06-07
      • 2014-05-27
      相关资源
      最近更新 更多