【问题标题】:Objective-C property - getter behaviourObjective-C 属性 - getter 行为
【发布时间】:2012-06-28 20:31:01
【问题描述】:

以下技术有什么问题:

@property(nonatomic, assign) NSUInteger timestamp;
@property(nonatomic, readonly, getter = timestamp) NSUInteger startTime;
@property(nonatomic, assign) NSUInteger endTime;

我确信我可以找到一种更好的方法来组织它,但这就是我在项目中的某个时刻得到的结果,我注意到 访问 startTime 属性总是返回 0,即使时间戳属性已设置为正确的时间戳

似乎已将 startTime 的 getter 设置为现有属性(时间戳),当我这样做时它不会转发时间戳的值:

event.startTime => 0
event.timestamp => 1340920893

顺便说一句,所有这些都是时间戳。

提醒一下,我知道上述情况应该发生在我的项目中,但我不明白为什么访问 startTime 不会转发到时间戳属性。

更新

在我的实现中,我正在综合所有这些属性:

@synthesize timestamp, endTime, startTime;

请查看我在 GitHub 上的 gist 中演示的示例对象:https://gist.github.com/3013951

【问题讨论】:

  • 错误是什么? getter?
  • 其实我的回答错了。如果您有多个属性链接到同一个选择器,这并不重要。我会说这没有问题......
  • @RichardJ.RossIII 我只在 ARC 项目的最新 XCode 中运行了我的测试。这可能是 Clang 在某个时候发生的变化。
  • 我在访问 startTime 时没有收到错误,但无论时间戳属性是什么,该值始终为 0。

标签: objective-c properties getter


【解决方案1】:

在您的描述方法中,您没有使用属性,而是在访问 ivar。

-(NSString*) description
{
    return [NSString stringWithFormat:@"Event< timestamp:%d, start:%d >", 
             timestamp, 
             startTime]; // <-- This is accessing the instance variable, not the property.
}

这对你有用:

-(NSString*) description
{
    return [NSString stringWithFormat:@"Event< timestamp:%d, start:%d >", 
             timestamp, 
             self.startTime]; // <-- This is using the property accessor.
}

property-vs-ivar 的事情总是把人们搞得一团糟,所以请原谅我在闲聊一分钟。 :) 如果您已经知道所有这些,请跳过。

当您创建和合成一个属性时,就像上面所做的那样,会发生两件事:

  1. 创建了正确类型的 ivar。
  2. 创建了一个 getter 函数,该函数返回该 ivar。

关于第 2 点的重要部分是,默认情况下,ivar 和 getter 函数(因此,属性)具有相同的名称

所以这个:

@interface Event
@property(nonatomic, assign) NSUInteger timestamp;
@property(nonatomic, readonly, getter = timestamp) NSUInteger startTime;
@end

@implementation Event
@synthesize timestamp, startTime;
@end

...变成这样:

@interface Event {
    NSUInteger timestamp;
    NSUInteger startTime;
}
@end

@implementation Event
- (NSUInteger) timestamp {
    return timestamp
}

- (void) setTimestamp:(NSUInteger) ts {
    timestamp = ts;
}

- (NSUInteger) startTime {
    return [self timestamp];
}
@end

点语法的工作原理是这样的:

NSUInteger foo = myEvent.startTime;

真的

NSUInteger foo = [myEvent startTime];

所有这一切都说明当您访问 ivar 时,您是在……嗯,访问 ivar。当您使用属性时,您正在调用一个返回值的函数。更重要的是,当你想要做另一件事时,做一件事是非常容易的,因为语法非常相似。正是由于这个原因,许多人经常将他们的 ivars 与前导下划线合成,这样就更难搞砸了。

@property(nonatomic, assign) NSUInteger timestamp;
@property(nonatomic, readonly, getter = timestamp) NSUInteger startTime;

@synthesize timestamp = _timestamp;
@synthesize startTime = _startTime;

NSLog( @"startTime = %d", _startTime );  // OK, accessing the ivar.
NSLog( @"startTime = %d", self.startTime );  // OK, using the property.
NSLog( @"startTime = %d", startTime );  // NO, that'll cause a compile error, and 
                                        // you'll say "whoops", and then change it 
                                        // to one of the above, thereby avoiding
                                        // potentially hours of head-scratching.  :)

【讨论】:

  • 当然。发现。太简单了,太复杂了!有时你会越过表面而过于深入地看待某事。我自己又是一个愚蠢的问题......谢谢你的回答。有趣的是,我通常使用下划线实现,但由于某种原因,我的这个类非常简单,我决定用更少的代码保留它。每日一课:保持你的编码风格。哦,在没有真正发疯之前不要在 Stack Overflow 上提问
【解决方案2】:

确保以正确的顺序进行合成,以便 startTime 存在 getter。

//implementation
@synthesize timestamp;
@synthesize statTime;

【讨论】:

  • 我没有特别注意这个的顺序,但事实证明我正在这样做。除非我需要在新行上专门设置合成。我正在做@synthesize p1、p2、p3;也许这不是没有优先考虑属性?
  • 您使用的是哪个编译器?我正在使用 Apple LLVM 3.1,它对我来说运行良好。
  • 我正在使用相同的。我刚刚发布了一个示例代码的链接,如果您愿意的话,请在您这边测试一下。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
  • 2011-11-07
  • 1970-01-01
  • 2011-06-10
相关资源
最近更新 更多