我所有的研究都表明@private指令没有真正的用途——所以我一定是遗漏了一些东西,需要各位专家加入:-)
假设我们有 2 个类:一个Car类和一个SportsCar类,其中SportsCar是Car的子类。
这是汽车类:
@interface Car : NSObject {
NSString *make;
NSString *model;
@private
int numberOfBackSeatPassengers; // I'm making this a private iVar cause I'm just gonna
// say that all Sportscars will be 2-seaters and therefore shouldn't
// be able to set/get the number of back-seat passengers
}
@property (nonatomic, strong) NSString *make, *model;
// Now here's my first issue: if I also make "numberOfBackSeatPassengers" an @property
// then it seems like all subclasses of this Car class *WILL* be able to access it as
// well - even though I declared it as @private - but I'll do this anyway to make my point:
@property int numberOfBackSeatPassengers;
@end
实现如下所示:
@implementation Car
@synthesize make, model, numberOfBackSeatPassengers;
@end
现在这里是跑车类:
#import "Car.h"
@interface Sportscar : Car
@property int turboEngineSize;
@end
及其实现:
#import "Sportscar.h"
@implementation Sportscar
@synthesize turboEngineSize;
@end
在“主要”我有这个:
Car *car1 = [[Car alloc] init];
[car1 setMake:@"Chevy"];
[car1 setModel:@"Impala"];
[car1 setNumberOfBackSeatPassengers:3];
Sportscar *sports1 = [[Sportscar alloc] init];
[sports1 setMake:@"Audi"];
[sports1 setModel:@"tt"];
[sports1 setNumberOfBackSeatPassengers:3];
显然,我可以在 Sportscar 上设置NumberOfBackSeatPassengers - 即使 iVar 被声明为@private - 但那是因为我在“ Car.h ”中将其设为 @property,这意味着它的合成 getter 和 setter 是 Instance方法,因此可用于Car的所有子类。
另一种选择是不在“Car.h”中将numberOfBackSeatPassengers声明为@property,仅将其保留为简单的 iVar,而是在“Car.m”的@implementation 中手动为其创建 Setter 和 Getter像这样:
-(void) setNumberOfBackSeatPassengers:(int)numPassgeners {
numberOfBackSeatPassengers = numPassgeners;
}
-(int)numberOfBackSeatPassengers {
return numberOfBackSeatPassengers;
}
这将使numberOfBackSeatPassengers的 getter 和 setter仅在“Car.m”中可用——我想这会使它们“私有”——但它们太私密了:我永远无法从 Main 或任何外部的任何地方调用它们“Car.m” 此外,这是真正的重点:这样做意味着“Car.h”中的 @private 指令在任何这些中都没有真正发挥作用。我的意思是我现在可以回到“Car.h”,在那里取出“ @private”指令——我的numberOfBackSeatPassengers的手动设置器和获取器仍然可以像现在一样工作,据说是私有的——那是什么通过“@private”获得 ? 它是如何真正发挥作用的?
任何人都可以对此有所了解吗?
(是的,我知道我可以在“Car.m”文件的@interface 部分扩展我的 Car 类 - 通过一个类别,或者先将numberOfBackSeatPassengers设为只读属性,然后将其更改为 readwrite 等 - 但这些都是似乎是使“@private”工作的变通方法或“黑客”。我只是不明白@private 如何真正独立工作。)
==================================================== ===
编辑 - 回应以下aroth的评论:
1) aroth 说子类在理论上仍然可以调用未在其父类的 Header 中声明的方法是绝对正确的——通过使用performSelector
. 我说“理论上”,因为在我的情况下它不能正常工作:如果 - 在“主要”中 - 我打电话
[sportscar1 performSelector:@selector(setNumberOfBackSeatPassengers:)];
然后我插入了一些垃圾号码,numberOfBackSeatPassengers
因为在以这种方式调用该方法时,我无法明确地将数字作为参数传入。
(问题:有没有办法解决这个问题?)
2) aroth 的说法也绝对正确,Sportscar
我们可以简单地覆盖Car
类的 setter 和 getter numberOfBackSeatPassengers
,并让这些覆盖方法将其重置为 0,或者给出错误等。但是虽然这是一个非常实用的解决方案,而且似乎可以解决这个特殊的问题,我觉得它并没有解决更大的问题,即@private
似乎没有真正做它应该做的事情。
3)重新设计逻辑以拥有一个类FourDoorCar
和另一个 类TwoDoorCar
,然后继续构建它是一个有趣的选择 - 但这几乎感觉就像现在 Objective-C 的语法正在“强制”我的编程逻辑以及我的方式构建我的项目——这感觉像是一种强加。也许我错了,并且对此做了太多 - 但无论哪种方式,这一切都只是因为@private
没有做它似乎承诺的事情......?感觉不对。
在一天结束时,我不断地回到同一个问题:@private
实际上对我们有什么好处?它有什么好处,它给我“买”了什么?似乎如果我想让 iVar 是私有的,我可以在“.m”文件中声明它,而不必首先在头文件中声明它。我的意思是我是否正确?或者是否仍然存在一些实例,您希望在 Header 中声明 iVar 为@private
,但不在Header 中为它声明 setter 和 getter - 所以这些不会显式地可用于子类 - 并让它全部感觉?
我们能想出一个实际的例子吗?是否有某种我想@private
在标题中声明的 Car 属性(而不是在“.m”中)会以某种方式使我受益?我认为numberOfBackSeatPassengers
这将是一个很好的例子,但我没有看到它在实际代码中如何真正起作用......
==================================================== ========================
编辑#2 - 继续与@aroth 对话:-)
@aroth - 我绝对同意它更好/更有条理地在标头中声明所有 iVar,而不是将内容拆分,以便有些在标头中,有些在实施中。这造成了混乱,我真的不喜欢这种方法。(我在最初的问题中指出,我不想使用实施和/或类别方法来解决我的问题。) -另外,是的,属性绝对不必总是由 iVar 支持。
-关于适当地设计类,我同意这当然是良好编程的关键。Car/Sportscar 的例子是我当场编造出来的,目的是为我的问题提供一些背景信息,考虑到它的设计优点/缺陷,我没有投入任何时间。我认为,如果我们采用您的方法 - 这似乎很合乎逻辑 - 并使用 Car 类、FourDoorCar 子类、TwoDoorCar 子类等 - 我们可以解决很多问题 - 但它仍然很可能迟早我们会遇到这样一种情况,我们可能想要一个 @private iVar 用于我们的一个类,并且不想创建另一个子类来处理它。我的意思是让我们假设这会发生,为了讨论。
因此,如果可能的话,我真的很想为我们的 Car 类考虑一个特定的 iVar,将其作为@private是有意义的,在代码中展示如何使用它,并讨论它的范围和限制。
我一直在想一个真实世界的例子,说明我们只希望 Car 拥有的 Car 的某些属性——并且它的任何子类都不应该继承。我真的认为numBackSeatPassengers
可以解决问题 - 就我们讨论的目的而言,它仍然可以,但是,我会再编一个并称它为phantomIVar
:-)
所以:
@interface Car : NSObject {
@private
//int numberOfBackSeatPassengers;
int phantomIVar;
}
@property (nonatomic, strong) NSString *make, *model;
@end
实施将是:
@implementation Car
@synthesize make, model;
-(void) setPhantomIVar:(int)i {
phantomIVar = i;
}
-(int)phantomIVar {
return phantomIVar;
}
@end
这几乎让我们回到了我们开始的地方:-)
至少我是这样的感觉。
@private
我的意思是声明似乎给我们带来的唯一好处是可读性。所以现在,任何查看 Header 的人都可以看到这phantomIVar
是 Car 的 iVar,并了解它是私有的。就是这样。
然而,就功能而言,它似乎并没有做太多。因为它不像把我们放在@private
前面phantomIVar
释放了我们仍然能够在 Header 中为它编写一个 setter/getter 并且只有 Car 类对象而不是 Car 的子类可以访问它们。不,@private
不明白。要获得隐私,您必须进入实施文件并在那里编写您的 setter 和 getter。最终在 Objective-C 中没有私有方法之类的东西。在对象。C. 他们都是公开的。
aroth,如果我做对了,请告诉我 - 如果没有,我到底哪里出错了。
非常感谢 :-)