@synthesized实例变量的可见性是多少?

时间:2011-12-14 19:26:15

标签: objective-c cocoa properties encapsulation

如果您的公共界面中有属性,如下所示

@interface MyClass : NSObject
@property(strong) NSString *myProp;
@end

然后合成它,实际上合成变量:

@implementation MyClass
@synthesize myProp = _myProp; // or just leave it at the default name..
@end

实例变量_myProp的可见性是多少?也就是说,这被视为@public@protected还是@private?我猜是因为MySubClass可以从MyClass继承,然后它也会获得属性(自然地),但它是否也会继承实例变量可见性?

如果我将属性放在类扩展中会有什么不同?这会将属性隐藏在子类中,我也猜测实例变量。这是在任何地方记录的吗?

5 个答案:

答案 0 :(得分:29)

合成的ivar 完全不可见所有无法看到@synthesize行的代码(基本上是指.m文件之外的任何内容)。它不是@protected,它不是@private,它只是未知。使用@private ivar,尝试访问它的其他代码将被告知它是私有的,但是使用合成的ivar,其他试图访问它的代码将被告知该字段根本不存在。

作为一个思想实验,试着想象一下ivar表现得像@protected的情况。你做了一个子类,然后在那里使用了ivar。现在,您返回超类并将@synthesize myProp更改为@synthesize myProp=foo。子类中会发生什么?当编译器处理子类时,无法看到 @synthesize行,所以它不知道你刚刚更改了ivar的名称。实际上,它甚至无法判断该属性是否完全由ivar支持,或者是否使用自定义编写的访问器方法实现。我希望很明显为什么这意味着子类不能访问ivar,也不能访问任何其他类。

那就是说,如果你在尝试访问ivar的同一个.m文件中编写代码,我不太清楚编译器会做什么。我希望它会将ivar视为@private(因为编译器实际上可以看到ivar存在)。

此外,这些都与运行时方法无关。其他类仍然可以使用obj-c运行时方法来动态查找类的ivar列表并使用它进行清理。

答案 1 :(得分:1)

如果在您的界面中声明它,那么在使用@property声明时它几乎是公开的。如果您想使用@property声明并将它们保持为私有属性,则应在实现中创建一个私有类别。

<强> MyClass.h

@interface MyClass : NSObject {
@private
    NSObject* foo;
}
@end

<强> MyClass.m

#import "ClassWithPrivateProperty.h"

@interface MyClass ()
    @property (nonatomic,retain) NSObject* foo; 
@end

@implementation MyClass
@synthesize foo;
// class implementation...
@end

答案 2 :(得分:1)

合成变量的作用就像声明@private

@interface Garble : NSObject
@property (copy) NSString * s; 
@end
@implementation Garble
@synthesize s;
@end

@interface Bargle : Garble
@end

@implementation Bargle

- (void) useS {
    NSLog(@"%@", s);    // error: instance variable 's' is private
}

@end

我发誓我在the docs看过这个,但我现在找不到它。如果我追踪它会更新。

答案 3 :(得分:1)

您可以创建一个动态属性,并向编译器指明其实例化将在运行时。

然后在你的子类中编写自己的getter或合成属性。

@interface BaseClass:NSObject

@property(nonatomic,strong)NSString * ThisWillBeSynthesizedInRespectiveSubclasses;

@end

@implementation BaseClass

@dynamic ThisWillBeSynthesizedInRespectiveSubclasses;

@end

在子类

@interface Subclass:BaseClass

@end

@implementation子类 @synthesize ThisWillBeSynthesizedInRespectiveSubclasses = _ThisWillBeSynthesizedInRespectiveSubclasses;

@end

或者你自己编写setter / getter方法。

希望这有帮助!

答案 4 :(得分:0)

其他课程可以访问#include的所有内容。换句话说,对于标题内的所有内容。

如果某些内容仅出现在您的实现文件中,则其他类(包括子类)不知道它存在。合成属性就是这样。其他类只知道属性(属性意味着getter和setter方法),但是他们对方法的内部实现一无所知。

请注意,obj-c中的访问说明符(public / private / protected)只是对编译器的提示,即使头文件中出现某些内容,也无法访问它。运行时不会以任何方式检查它。

如果将其放入类扩展中会发生什么?请注意,属性是一组两种方法。您只需隐藏包含类主标题但不包含类扩展标题的每个类的方法。

我们使用它来举例说明一个属性为readonly,在类继续中我们将它声明为readwrite。然后,我们只能从类的内部使用setter。