当你声明 a@property
时,编译器会自动合成带有下划线前缀的变量、getter 方法和 setter 方法。
@interface MyClass ()
@property(strong, nonatomic) NSString *myString;
@end
在这个例子中,编译器会将变量 syhtnesize as _myString
,getter as
-(NSString *)myString
和二传手为
-(void)setMyString:(NSString *)string
“@property”之后的关键字(strong, nonatomic)
定义了属性的属性。strong
,默认值,意味着所有权,这意味着在这种情况下,MyClass
实例将基本上负责其各自myString
对象的保留/释放。nonatomic
意味着变量不能保证在多线程环境中始终是有效值,例如,如果 getter 与 setter 同时被调用。
此外,编译器会将用于检索/设置实例变量的点语法视为对适当 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 的Objective-C 编程指南。
至于你的具体问题:
1. 如果我们可以只创建两个属性,那么一开始就在那里声明它们有什么意义?
实际上,在文件中(或在大多数其他情况下)将变量显式声明为公共变量并不是一个好主意。MyClass.h
相反,将它们声明为属性会自动创建一个私有变量(和访问器方法),从而更容易遵循 OOP 最佳实践。所以声明没有意义
// MyClass.h
@interface MyClass : NSObject {
NSString *myString // public variables not good
}
也因为我上面提到的点语法,如果你self.myString
在内部MyClass.m
或instanceOfMyClass.myString
外部使用,公共变量myString
甚至不会被触及,因为合成变量被命名为_myString
.
2. 为什么要创建两个实例变量和属性来对应它们?
见上文——您不需要两个实例变量,只需要一个。
3. 我知道我们可以在 .m 中声明变量,而不是让它们对类和子类的所有内容都是私有的。这里有什么区别?我觉得我错过了很多基础知识。有没有一种简单的方式来看待这一切?
如果您在文件的@implementation
一部分中私下声明变量.m
,编译器将无法通过合成 getter 和 setter 来帮助您。即使作为私有方法,getter 和 setter 也可以帮助降低代码的复杂性,例如检查变量值的有效性。(注意:您可以覆盖访问器方法。)
// 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 方法。