【问题标题】:Lazy loading Objective-C class with int properties延迟加载具有 int 属性的 Objective-C 类
【发布时间】:2014-01-07 04:17:25
【问题描述】:

我使用以下内容作为我的一个类中的属性的获取器:

- (NSString *)version
{
    if (_version == nil) {
        _version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
    }
    return _version;
}

这很好用。但是,当我对 int 属性尝试相同的操作时,我显然会得到一个错误,因为 int 永远不会为零。解决这个问题的最佳方法是什么?

- (int)numberOfDays
{
    if (_numberOfDays == nil) {
        // relatively memory intense calculation that works out numberOfDays:
        _numberOfDays = X;
    }    
    return _numberOfDays;
}

【问题讨论】:

  • 要么使用一个你知道不会出现的值(可能是 -1?),或者更清楚地说,只使用一个 BOOL 字段(例如_numberOfDaysComputed)。
  • dispatch_once(&token, ^{ hard_computation(); });
  • @H2CO3:这应该是一个答案。

标签: objective-c class properties int null


【解决方案1】:

首先,如果可能的话,不推荐使用 int。如果你需要使用原始整数类型,你应该使用NSInteger。 NSInteger 的大小在编译时根据所构建的体系结构确定。 int 是一个静态大小,不会针对不同的架构扩大。用起来没问题,注意就好。

使用 NSInteger,你仍然面临同样的问题,它不能为零。因此,您应该将您的属性设为NSNumber,您可以使用[NSNumber numberWithInteger:anInteger]; 的计算结果对其进行初始化。这样,您就可以对您的财产进行零检查,并且只进行一次计算以创建您的 NSNumber

【讨论】:

  • 为什么不能在 Objective-C 中使用int
  • 我刚刚解释过了。看到这个答案stackoverflow.com/questions/4445173/…
  • “它在不同的架构上有不同的大小”不是解释,因为int 也是如此。此外,您链接到的答案也有不少人不同意。
  • @H2CO3,就像一个注释:int 在我们谈论的任何平台上都不会改变大小。它始终是 32 位的。它可能不同,但它永远不会出现在 Apple 世界中,而且几乎可以肯定永远不会。
  • @RobNapier iOS 不是世界上唯一的操作系统 ;-) 另外,“int 是一个静态大小,不会针对不同的架构进行优化。” - 特别不正确。如果我们正在分裂头发,让我们正确地做:在 C 中,int 被认为/建议是最快的整数类型。所以如果我们做这样的优化(why?),那就更好用了。当然,范围可能是一个真正的问题。事实上,如果有一个应用程序依赖于尽可能宽的整数类型,那么它应该是NSInteger——但除此之外,typedef 没有任何其他真正的优势。
【解决方案2】:

添加另一个布尔实例变量_numberOfDaysCalculated。 线程安全版本将是

- (int)numberOfDays
{
    @synchronized(self) {
        if (!_numberOfDaysCalculated) {
            // relatively memory intense calculation that works out numberOfDays:
            _numberOfDays = X;
            _numberOfDaysCalculated = YES;
        }
    }    
    return _numberOfDays;
}

或者,如果该属性有一些“无效”值,您可以使用它 作为“尚未计算”的标记。例如,如果numberOfDays 的计算值必须为非负数,您可以在init 方法中初始化_numberOfDays = -1, 然后在惰性getter方法中测试if (_numberOfDays == -1)

【讨论】:

  • 呃,所以你也添加了“sentinel value out of range”方法,我明白了:)
【解决方案3】:

使用 GCD。

static dispatch_once_t tok;
dispatch_once(&tok, ^{ memory_intensive_computation(); });

不,不要使用 GCD,我没有抓住重点。在实例方法中,您希望将信息绑定到每个实例,因此使用静态调度令牌是不合适的。也许你应该坚持使用“布尔标志作为实例变量”的方法。

或者,您可以将int 初始化为一个已知超出其有效范围的值(例如,我认为numberOfDays 永远不能为负数)并将其用作执行计算的条件.

【讨论】:

  • - (int)numberOfDays是一个实例方法,每个实例都有自己的_version。所以你不能使用静态 dispatch_once_t。并且使用dispatch_once_t谓词作为成员变量似乎是不允许的,比较stackoverflow.com/questions/13856037/…
  • @MartinR 嗯,我错过了。当然你是对的,让我再考虑一下。
  • @MartinR:Yowza,我也不知道动态存储限制。多麻烦啊。我想知道这是怎么回事。
  • 这是因为他们使用实际内存位置作为“我已经完成这个”标记。它必须是永远不会改变的东西。
  • 据我所知,Greg Parker 来自 Apple,他将这个答案 stackoverflow.com/a/19845164/1187415 发布到上述线程。
【解决方案4】:

使用 NSNumber 来存储 int 值。

- (int)numberOfDays
{
    if (_numberOfDays == nil) {
        // relatively memory intense calculation that works out numberOfDays:
        _numberOfDays = @(X);
    }    
    return [_numberOfDays intValue];
}

【讨论】:

  • IMO,NSNumber 解决方案是迄今为止这里提供的最佳方法。它简单、一致、可靠且快速。
  • 这是否涉及属性是 NSNumber 而不是 int?
  • @CharlieSeligman:实例变量 _numberOfDays 将是一个 NSNumber。属性 numberOfDays 仍然是一个 int。
【解决方案5】:

我会在 -init 中使用 NSNotFound 初始化 _numberOfDays,并在 getter 中对其进行测试。

【讨论】:

    猜你喜欢
    • 2013-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多