我已经写了几年Objective-C,并决定回去学习基础知识,以帮助我编写更好的代码。我试图学习所有关于实例变量,继承和类扩展的知识。我已经阅读了所有这三个,但有一件事令我难以理解。我有一个简单的应用程序,包含2个类,Person,Male(继承自Person),当然还有Main(导入Male类,因此能够访问Person和Male中的实例变量)。
代码很简单,为了空间我不会发布所有内容。 Main基本上采用这些变量并与它们一起玩。这是令我难以置信的部分:
@interface Person : NSObject {
float heightInMeters;
int weightInKilos;
}
@property float heightInMeters;
@property int weightInKilos;
@end
当我删除括号和变量声明时,将其保留为:
@interface Person : NSObject
@property float heightInMeters;
@property int weightInKilos;
@end
代码仍然继承并执行得很好。
1。如果我们可以创建两个属性,那么即使在那里首先声明它们有什么意义呢?
2。为什么要创建两个实例变量AND属性以与它们对应?
3。我知道我们可以在.m中声明变量,而不是让它们对类及其子类化的所有内容都是私有的。像这样:
@implementation Person {
float heightInMeters;
int weightInKilos;
}
这有什么区别?我觉得我缺少很多基础知识。是否有一种简单的方式将这一切都放在一边?
答案 0 :(得分:2)
当您声明@property
时,编译器将自动合成前缀为下划线的变量,getter方法和setter方法。
@interface MyClass ()
@property(strong, nonatomic) NSString *myString;
@end
在此示例中,编译器会将变量同形化为_myString
,将getter合并为
-(NSString *)myString
和setter为
-(void)setMyString:(NSString *)string
" @ property"之后的关键字(strong, nonatomic)
定义属性的属性。默认情况下,strong
表示所有权,这意味着在这种情况下MyClass
个实例将主要负责保留/释放各自的myString
个对象。 nonatomic
表示不保证变量在多线程环境中始终是有效值,例如,如果与setter同时调用getter。
此外,编译器会将用于检索/设置实例变量的点语法视为对相应getter / setter方法的调用。因此,给定一个MyClass的实例
MyClass *exampleClass = [[MyClass alloc] init];
以下两个都是等同的陈述:
NSString *string1 = example.myString; // dot syntax
NSString *string1 = [example myString]; // explicit call to the getter method
如需进一步阅读,请查看Apple的Programming with Objective-C Guide。
至于你的具体问题:
MyClass.h
文件(或大多数其他情况)declare variables explicitly as public variables实际上不是一个好主意。相反,将它们声明为属性会自动创建一个私有变量(和访问器方法),从而使OOP最佳实践更容易实现。所以宣布
// MyClass.h
@interface MyClass : NSObject {
NSString *myString // public variables not good
}
另外,由于我上面提到的点语法,如果你在self.myString
或MyClass.m
内部使用instanceOfMyClass.myString
,公共变量myString
将永远不会被触及因为合成变量名为_myString
。
见上文 - 您不需要两个实例变量,只需要一个。
如果您在@implementation
文件的.m
部分私下声明变量,则编译器无法通过合成getter和setter来帮助您。即使私有方法,getter和setter也可以帮助降低代码的复杂性,例如检查变量值的有效性。 (注意:你可以override accessor methods。)
// MyClass.m
@interface MyClass () // private interface
@property(nonatomic, strong) NSString *myString;
@end
@implementation MyClass {
// no more need for private variables!
// compiler will synthesize NSString *_myString and accessors
}
-(void)setMyString:(NSString *)string { // overwrite setter
// no empty strings allowed in our object (for the sake of example)
NSAssert([string length] > 0, @"String must not be empty");
// assign private instance variable in setter
_myString = string;
}
@end
这样,即使你继承了MyClass
,子类也会继承编译器为我们合成的getter和setter方法。