为什么在Objective-C的头文件中定义了实例变量

时间:2022-09-07 07:37:55

I can understand defining the functions in the @interface of the header file, but why the instance variables? Shouldn't the instance variables be private, only accessible through messages?

我可以理解在头文件的@interface中定义函数,但为什么实例变量?实例变量不应该是私有的,只能通过消息访问吗?

6 个解决方案

#1


The reason is so it can calculate offsets of variables for subclasses.

原因是它可以计算子类的变量偏移量。

@interface Bird : NSObject {
    int wingspan;
}
@end
@interface Penguin : Bird {
    NSPoint nestLocation;
    Penguin *mate;
}
@end

Without knowing the structure of the "Bird" class, the "Penguin" class can't calculate the offset of its fields from the beginning of the structure. The penguin structure looks kind of like this:

在不知道“Bird”类的结构的情况下,“Penguin”类无法从结构的开头计算其字段的偏移量。企鹅结构看起来像这样:

struct Penguin {
    int refcount; // from NSObject
    int wingspan; // from Bird
    NSPoint nestLocation; // from Penguin
    Penguin *mate; // from Penguin
}

This has a side effect: if you change the size of a class in a library, you break all the subclasses in apps that link to that library. The new properties work around this problem.

这有副作用:如果更改库中类的大小,则会中断链接到该库的应用程序中的所有子类。新属性解决此问题。

#2


Although they are declared in the header file, all instance variable in Objective-C have @protected access by default. This means the variable is accessible within the class that declares it and any class inheriting from that class.

虽然它们是在头文件中声明的,但是Objective-C中的所有实例变量都默认具有@protected访问权限。这意味着变量可以在声明它的类和从该类继承的任何类中访问。

Here is Apple's documentation on defining an Objective-C class: Defining Classes

以下是Apple关于定义Objective-C类的文档:定义类

Notice the section titled "The Scope of Instance Variables".

请注意标题为“实例变量的范围”的部分。

#3


I think it is a technical issue. If I understand correctly, a Objective-C class is just a fancy C struct. And for a struct to be used its size must be known. (Like how would sizeof() work otherwise)

我认为这是一个技术问题。如果我理解正确,Objective-C类只是一个奇特的C结构。对于要使用的结构,必须知道它的大小。 (就像sizeof()如何工作)

#4


In case anyone stumbles across this question -- as of XCode 4.2 with the LLVM compiler, you can declare instance variables in the @implementation using the following brace notation:

如果有人遇到这个问题 - 从使用LLVM编译器的XCode 4.2开始,您可以使用以下括号表示法在@implementation中声明实例变量:


@interface SomeClass : NSObject
@end

@implementation SomeClass {
  NSString *myInstanceVariable_;
}

- (void)moreMethods {}
@end

Instance variables generally shouldn't be part of your classes declared public interface -- they're implementation details.

实例变量通常不应该是声明为public interface的类的一部分 - 它们是实现细节。

However, MAKE SURE you define your instance variables within the braces or else you'll be defining a global variable that has no relation to the object instance:

但是,确保在大括号内定义实例变量,否则您将定义与对象实例无关的全局变量:


@implementation SomeClass
  NSString *whoopsGlobalVariable_;

- (void)moreMethods {}

@end

#5


Taken from the section of Apple's documentation on defining Objective-C classes, The Role of the Interface:

摘自Apple关于定义Objective-C类的文档部分,接口的角色:

Although instance variables are most naturally viewed as a matter of the implementation of a class rather than its interface, they must nevertheless be declared in the interface file. This is because the compiler must be aware of the structure of an object where it’s used, not just where it’s defined.

尽管实例变量最自然地被视为类的实现而不是其接口,但它们必须在接口文件中声明。这是因为编译器必须知道使用它的对象的结构,而不仅仅是它定义的位置。

#6


Note that under the Objective C 2.0 new "Modern Runtime" (availabe in iPhone applications and 64-bit Mac OS X 10.5 applications) you do not need to specify the ivars, you can specify the properties and then use @synthesize to generate the ivars.

请注意,在Objective C 2.0下新的“Modern Runtime”(可在iPhone应用程序和64位Mac OS X 10.5应用程序中使用),您不需要指定ivars,您可以指定属性,然后使用@synthesize生成ivars 。

This is because in the Modern Runtime, ivars have a global indirection symbol that holds the offset for the ivar. This also resolves the fragile base class issue, allowing ivars to be reordered and added without requiring recompiling of subclasses (deleting or renaming ivars may still cause link errors).

这是因为在Modern Runtime中,ivars有一个全局间接符号,用于保存ivar的偏移量。这也解决了脆弱的基类问题,允许重新排序和添加ivars而无需重新编译子类(删除或重命名ivars仍可能导致链接错误)。

However you still have to list properties in the main interface, so there does not seem to be any way to entirely hide private ivars which is unfortunate. You cannot, for example, use a property and @synthesize in a category.

但是你仍然需要在主界面中列出属性,所以似乎没有任何方法可以完全隐藏不幸的私有ivars。例如,您不能在类别中使用属性和@synthesize。

#1


The reason is so it can calculate offsets of variables for subclasses.

原因是它可以计算子类的变量偏移量。

@interface Bird : NSObject {
    int wingspan;
}
@end
@interface Penguin : Bird {
    NSPoint nestLocation;
    Penguin *mate;
}
@end

Without knowing the structure of the "Bird" class, the "Penguin" class can't calculate the offset of its fields from the beginning of the structure. The penguin structure looks kind of like this:

在不知道“Bird”类的结构的情况下,“Penguin”类无法从结构的开头计算其字段的偏移量。企鹅结构看起来像这样:

struct Penguin {
    int refcount; // from NSObject
    int wingspan; // from Bird
    NSPoint nestLocation; // from Penguin
    Penguin *mate; // from Penguin
}

This has a side effect: if you change the size of a class in a library, you break all the subclasses in apps that link to that library. The new properties work around this problem.

这有副作用:如果更改库中类的大小,则会中断链接到该库的应用程序中的所有子类。新属性解决此问题。

#2


Although they are declared in the header file, all instance variable in Objective-C have @protected access by default. This means the variable is accessible within the class that declares it and any class inheriting from that class.

虽然它们是在头文件中声明的,但是Objective-C中的所有实例变量都默认具有@protected访问权限。这意味着变量可以在声明它的类和从该类继承的任何类中访问。

Here is Apple's documentation on defining an Objective-C class: Defining Classes

以下是Apple关于定义Objective-C类的文档:定义类

Notice the section titled "The Scope of Instance Variables".

请注意标题为“实例变量的范围”的部分。

#3


I think it is a technical issue. If I understand correctly, a Objective-C class is just a fancy C struct. And for a struct to be used its size must be known. (Like how would sizeof() work otherwise)

我认为这是一个技术问题。如果我理解正确,Objective-C类只是一个奇特的C结构。对于要使用的结构,必须知道它的大小。 (就像sizeof()如何工作)

#4


In case anyone stumbles across this question -- as of XCode 4.2 with the LLVM compiler, you can declare instance variables in the @implementation using the following brace notation:

如果有人遇到这个问题 - 从使用LLVM编译器的XCode 4.2开始,您可以使用以下括号表示法在@implementation中声明实例变量:


@interface SomeClass : NSObject
@end

@implementation SomeClass {
  NSString *myInstanceVariable_;
}

- (void)moreMethods {}
@end

Instance variables generally shouldn't be part of your classes declared public interface -- they're implementation details.

实例变量通常不应该是声明为public interface的类的一部分 - 它们是实现细节。

However, MAKE SURE you define your instance variables within the braces or else you'll be defining a global variable that has no relation to the object instance:

但是,确保在大括号内定义实例变量,否则您将定义与对象实例无关的全局变量:


@implementation SomeClass
  NSString *whoopsGlobalVariable_;

- (void)moreMethods {}

@end

#5


Taken from the section of Apple's documentation on defining Objective-C classes, The Role of the Interface:

摘自Apple关于定义Objective-C类的文档部分,接口的角色:

Although instance variables are most naturally viewed as a matter of the implementation of a class rather than its interface, they must nevertheless be declared in the interface file. This is because the compiler must be aware of the structure of an object where it’s used, not just where it’s defined.

尽管实例变量最自然地被视为类的实现而不是其接口,但它们必须在接口文件中声明。这是因为编译器必须知道使用它的对象的结构,而不仅仅是它定义的位置。

#6


Note that under the Objective C 2.0 new "Modern Runtime" (availabe in iPhone applications and 64-bit Mac OS X 10.5 applications) you do not need to specify the ivars, you can specify the properties and then use @synthesize to generate the ivars.

请注意,在Objective C 2.0下新的“Modern Runtime”(可在iPhone应用程序和64位Mac OS X 10.5应用程序中使用),您不需要指定ivars,您可以指定属性,然后使用@synthesize生成ivars 。

This is because in the Modern Runtime, ivars have a global indirection symbol that holds the offset for the ivar. This also resolves the fragile base class issue, allowing ivars to be reordered and added without requiring recompiling of subclasses (deleting or renaming ivars may still cause link errors).

这是因为在Modern Runtime中,ivars有一个全局间接符号,用于保存ivar的偏移量。这也解决了脆弱的基类问题,允许重新排序和添加ivars而无需重新编译子类(删除或重命名ivars仍可能导致链接错误)。

However you still have to list properties in the main interface, so there does not seem to be any way to entirely hide private ivars which is unfortunate. You cannot, for example, use a property and @synthesize in a category.

但是你仍然需要在主界面中列出属性,所以似乎没有任何方法可以完全隐藏不幸的私有ivars。例如,您不能在类别中使用属性和@synthesize。