宣称的私人ivars与合成的ivars有何不同?

时间:2010-03-21 16:08:32

标签: objective-c

我知道现代的Objective-C运行时可以合成ivars。我认为合成的ivars的行为与标记为@private的声明的ivars完全相同,但它们没有。

因此,代码仅在我预期可以处理的现代运行时下进行编译。例如,超类:

@interface A : NSObject {
#if !__OBJC2__
  @private
    NSString *_c;
#endif
}

@property (nonatomic, copy) NSString *d;

@end


@implementation A

@synthesize d=_c;

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

@end

和一个子类:

@interface B : A {
#if !__OBJC2__
@private
    NSString *_c;
#endif
}

@property (nonatomic, copy) NSString *e;

@end


@implementation B

@synthesize e=_c;

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

@end

子类不能具有声明的ivar,其名称与其超类的声明的ivar同名,即使超类的ivar是私有的。这似乎违反了@private的含义,因为子类受到超类选择私有的影响。

然而,我更关心的是我应该如何看待合成的伊娃。我认为他们的行为就像宣布的私人伊娃,但没有脆弱的基类问题。也许这是正确的,我只是不明白脆弱的基类问题。为什么上面的代码只在现代运行时编译?当所有超类实例变量都是私有的时,是否存在脆弱的基类问题?

2 个答案:

答案 0 :(得分:6)

合成的ivars 私有的。你所看到的是编译器正常工作。

忽略!__OBJ2__条件中的代码。我只会看一下合成的ivars案例。

这是您的代码所具有的:

  • A::_c是合成的ivar,是 只能在 实施A
  • B::_c是一个 合成ivar并且是唯一的 在实施中可访问 B

它们不是同一个变量。它们不会发生冲突,也不会存储相同的值。

仍然可能出现问题的情况......

如果您尝试将AB的实现放在同一个文件中,编译器现在可以在编译时看到A::_c的声明B 并阻止您访问_c@synthesize e=_c;行中的B

为什么要这样做?我不是说A::_cB::_c是分开的,不相关的变量吗?

将两个实现放在同一个文件中会导致当编译器到达_c@synthesize e=_c;不是未声明的标识符,因此编译器不会尝试为{{1}创建新的合成ivar相反,它尝试访问B并失败(因为A::_c是私有的)。

答案 1 :(得分:2)

简而言之,你不能[拥有私人ivars]。

另一种方法是在实现文件中声明一个包含所有状态的类,然后将其视为结构。

的.m:

@interface PrivateGoo:NSObject
{... ivars ...}
... props
@end

@implementation PrivateGoo
... @synth or not

然后,在.h中,声明像id privateGoop;这样的ivar。如果查找速度很可怕,请在.m文件中使用((PrivateGoo*)privateGoop)->iVar;。如果你这样做,请注意内存管理。

请注意,这有几个优点,即使乍一看似乎很奇怪。也就是说,它使PrivateGoo的重构变得微不足道;如果您的数据封装突然发现需要具有业务逻辑或者更普遍可用,那么这样做是微不足道的。使用GC,编译器将为PrivateGoo设置布局信息,并将完全自动管理所有内存。使用结构需要稍微跳圈以使工作正确 - 正确的分配模式等。


抱歉 - 实际上没有回答这个问题。

合成的ivars与常规的ivars完全相同,只是你不必在标题中声明'em'。除此之外,没有任何特别的私密性。请注意,不需要合成的ivars来避免脆弱的基类问题。

为了编译器的利益,存在@private@protected@public指令;当你访问被声明为不可访问的东西时给它一个警告(或错误)的钩子。对于内容,仍然存在OBjective-C相对平坦的命名空间,这就是阻止你在子类中使用同名iVar的原因。

脆弱的基类问题与属性和合成的ivars正交。脆弱的基类在iPhone OS和64位Mac OS X上的现代Objective-C 2.0 ABI中得到了解决。由于二进制兼容性原因,32位Mac OS X保留了传统行为。