0

我已经编写 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.为什么要创建两个实例变量和属性来与之对应?

3.我知道我们可以在 .m 中声明变量,而不是让它们对类和子类的所有内容都是私有的。像这样:

    @implementation Person {
    float heightInMeters;
    int weightInKilos;
    }

这里有什么区别?我觉得我错过了很多基础知识。有没有一种简单的方式来看待这一切?

4

1 回答 1

2

当你声明 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.minstanceOfMyClass.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 方法。

于 2014-10-31T19:10:51.700 回答