I'm rather confused about properties and instance variables in Objective-C.
我对Objective-C中的属性和实例变量很困惑。
I'm about half-way through Aaron Hillegass's "Cocoa Programming for Mac OS X" and everything is logical. You would declare a class something like this:
我已经看了Aaron Hillegass的《Mac OS X的Cocoa编程》一半了,一切都是合乎逻辑的。你可以这样声明一个类:
@class Something;
@interface MyClass : NSObject {
NSString *name;
NSArray *items;
Something *something;
IBOutlet NSTextField *myTextField;
}
@property (nonatomic, retain) NSString *name;
@property (nonatomic, retain) NSArray *items;
-
Since other objects need to manipulate our
name
anditems
instance variables, we use@property
/@synthesize
to generate accessors/mutators for them. Within our class, we don't use the accessors/mutators—we just interact with the instance variable directly.由于其他对象需要操作我们的名称和项目实例变量,所以我们使用@property/@synthesize为它们生成访问器/修改器。在我们的类中,我们不使用访问器/mutators——我们直接与实例变量交互。
-
something
is just an instance variable that we're going to use in our class, and since no one else needs to use it, we don't create a pair of accessors and mutators for it.某些东西只是我们要在类中使用的一个实例变量,由于没有人需要使用它,所以我们不会为它创建一对访问器和修改器。
-
We need to interact with a text field in our UI, so we declare an
IBOutlet
for it, connect it, and we're done.我们需要在UI中与一个文本字段交互,因此我们为它声明一个IBOutlet,连接它,然后就完成了。
All very logical.
都很合乎逻辑的。
However, in the iPhone world, things seem to be different. People declare properties for every single instance variable, declare properties for IBOutlets
, and use accessors/mutators to interact with instance variables within the class (e.g. they would write [self setName:@"Test"]
rather than name = @"Test"
).
然而,在iPhone世界里,事情似乎有所不同。人们为每个实例变量声明属性,为iboutlet声明属性,并使用访问器/mutators与类中的实例变量进行交互(例如,他们将写入[self setName:@"Test"],而不是name = @"Test")。
Why? What is going on? Are these differences iPhone-specific? What are the advantages of declaring properties for all instance variables, declaring properties for IBOutlets
, and using accessors/mutators within your own class?
为什么?什么是怎么回事?仅需点击这些差异呢?为所有实例变量声明属性、为iboutlet声明属性以及在自己的类中使用访问器/修改器的优点是什么?
5 个解决方案
#1
29
In the iPhone world, there's no garbage collector available. You'll have to carefully manage memory with reference counting. With that in mind, consider the difference between:
在iPhone世界中,没有可用的垃圾收集器。您必须小心地使用引用计数管理内存。考虑到这一点,请考虑以下两者之间的区别:
name = @"Test";
and
和
self.name = @"Test";
// which is equivalent to:
[self setName: @"Test"];
If you directly set the instance variable, without prior consideration, you'll lose the reference to the previous value and you can't adjust its retain count (you should have release
d it manually). If you access it through a property, it'll be handled automatically for you, along with incrementing the retain count of the newly assigned object.
如果您直接设置实例变量,没有事先考虑,您将丢失对先前值的引用,并且您不能调整它的保留计数(您应该手动释放它)。如果您通过属性访问它,它将自动为您处理,并增加新分配对象的retain count。
The fundamental concept is not iPhone specific but it becomes crucial in an environment without the garbage collector.
基本概念不是针对iPhone的,但在没有垃圾收集器的环境中,它变得至关重要。
#2
6
Properties are used to generate accessors for instance variables, there's no magic happening.
属性用于为实例变量生成访问器,没有什么神奇的事情发生。
You can implement the same accessors by hand.
您可以手工实现相同的访问器。
You can find in Aaron Hillegass's book examples of 3 memory management strategies for member variables. They are assign/copy/retain
. You select one of those as required for given variable.
你可以在Aaron Hillegass的书中找到关于成员变量的3种内存管理策略的例子。他们分配/复制/保留。您可以根据给定变量的需要选择其中之一。
I assume you understand memory management in Objective-c ...
我猜你理解Objective-c中的内存管理…
Accessors hide the complexity and differences of memory management for each variable.
访问器隐藏了每个变量的内存管理的复杂性和差异。
For example:
例如:
name = @"Test"
is a simple assignment, name
now holds reference to NSString @"Test"
. However you could decide to use copy
or retain
. No matter which version of memory management you chose accessor hides the complexity and you always access the variable with (or similar):
是一个简单的赋值,name现在包含对NSString @“Test”的引用。但是,您可以决定使用copy或retain。不管您选择的是哪个版本的内存管理器,都隐藏了复杂性,您总是使用(或类似的)访问变量:
[self setName:@"Test"]
[self name]
Now setName:
might use assign/copy or retain
and you don't have to worry about it.
现在setName:可以使用assign/copy或retain,您不必担心它。
My guess is that iPhone tutorials use properties to make it easier for new developers to jump through memory management (even though it's handy to generate appropriate accessors with properties rather than implement them by hand every time).
我的猜测是,iPhone教程使用属性使新开发人员更容易进行内存管理(尽管用属性生成适当的访问器比每次手工实现更方便)。
#3
3
However, in the iPhone world, things seem to be different. People declare properties for every single instance variable, declare properties for
IBOutlets
, and use accessors/mutators to interact with instance variables within the class (e.g. they would write[self setName:@"Test"]
rather thanname = @"Test"
).然而,在iPhone世界里,事情似乎有所不同。人们为每个实例变量声明属性,为iboutlet声明属性,并使用访问器/mutators与类中的实例变量进行交互(例如,他们将写入[self setName:@"Test"],而不是name = @"Test")。
That's not iPhone-specific. Except in init
methods and the dealloc
method, it's good practice to always use your accessors. The main benefit, especially on the Mac (with Cocoa Bindings), is that using your accessors means free KVO notifications.
这不是于iphone。除了init方法和dealloc方法之外,最好始终使用访问器。主要的好处是,特别是在Mac上(带有Cocoa绑定),使用访问器意味着免费的KVO通知。
The reason why people “declare properties for every single instance variable” is most probably that all of their instance variables are things they want to expose as properties. If they had something they would want to keep private, they would not declare a property for it in the header file. (However, they may make a property for it in a class extension in the implementation file, in order to get the aforementioned free KVO notifications.)
人们“为每个实例变量声明属性”的原因很可能是他们所有的实例变量都是他们希望作为属性公开的东西。如果他们想要保持私有,他们不会在头文件中为它声明属性。(但是,他们可以在实现文件的类扩展名中为它创建一个属性,以便获得上述免费的KVO通知。)
Declaring properties for outlets is overkill, in my opinion. I don't see a point to it. If you don't make a property, the nib loader will set the outlet by direct instance-variable access, which is just fine for that task.
在我看来,为outlet声明属性有些过头了。我看不出有什么意义。如果不创建属性,nib加载程序将通过直接实例变量访问来设置outlet,这对该任务来说很好。
#4
2
I would suggest that modern development has made a very strong attempt to identify, define and apply best practices.
我认为,现代发展已经作出了非常有力的努力来确定、定义和应用最佳实践。
Among these best practices we find continuity and consistency.
在这些最佳实践中,我们发现了连续性和一致性。
Apart from arguing over use of accessors in init
and dealloc
methods, accessors should generally be used all the time (inside and outside of a class) for the benefits they offer, including encapsulation, polymorphic var implementations (which both allow for abstracting and refactoring) and to facilitate those best practices of continuity and consistency. The fundamental benefits of an object-orient language come into play when doing things in this way and exploiting the fullness of the language's capabilities. Always being consistent in one's coding is an oft undermentioned benefit, as any senior programmer will usually attest.
除了争论在init和dealloc方法,使用访问器访问器一般应使用所有的时间(一个类的内部和外部)他们提供的好处,包括封装、多态var(允许提取和重构)实现和促进这些最佳实践的连续性和一致性。面向对象语言的基本好处在以这种方式做事并充分利用语言的功能时发挥了作用。在一个人的编码中始终如一是一个经常被提及的好处,正如任何高级程序员通常会证明的那样。
#5
0
You can write like this
你可以这样写
//MyClass.h
@class Something;
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *items;
@end
//MyClass.m
@interface MyClass()
@property (nonatomic, strong) IBOutlet NSTextField *myTextField;
@property (nonatomic, strong) Something *something;
@end
#1
29
In the iPhone world, there's no garbage collector available. You'll have to carefully manage memory with reference counting. With that in mind, consider the difference between:
在iPhone世界中,没有可用的垃圾收集器。您必须小心地使用引用计数管理内存。考虑到这一点,请考虑以下两者之间的区别:
name = @"Test";
and
和
self.name = @"Test";
// which is equivalent to:
[self setName: @"Test"];
If you directly set the instance variable, without prior consideration, you'll lose the reference to the previous value and you can't adjust its retain count (you should have release
d it manually). If you access it through a property, it'll be handled automatically for you, along with incrementing the retain count of the newly assigned object.
如果您直接设置实例变量,没有事先考虑,您将丢失对先前值的引用,并且您不能调整它的保留计数(您应该手动释放它)。如果您通过属性访问它,它将自动为您处理,并增加新分配对象的retain count。
The fundamental concept is not iPhone specific but it becomes crucial in an environment without the garbage collector.
基本概念不是针对iPhone的,但在没有垃圾收集器的环境中,它变得至关重要。
#2
6
Properties are used to generate accessors for instance variables, there's no magic happening.
属性用于为实例变量生成访问器,没有什么神奇的事情发生。
You can implement the same accessors by hand.
您可以手工实现相同的访问器。
You can find in Aaron Hillegass's book examples of 3 memory management strategies for member variables. They are assign/copy/retain
. You select one of those as required for given variable.
你可以在Aaron Hillegass的书中找到关于成员变量的3种内存管理策略的例子。他们分配/复制/保留。您可以根据给定变量的需要选择其中之一。
I assume you understand memory management in Objective-c ...
我猜你理解Objective-c中的内存管理…
Accessors hide the complexity and differences of memory management for each variable.
访问器隐藏了每个变量的内存管理的复杂性和差异。
For example:
例如:
name = @"Test"
is a simple assignment, name
now holds reference to NSString @"Test"
. However you could decide to use copy
or retain
. No matter which version of memory management you chose accessor hides the complexity and you always access the variable with (or similar):
是一个简单的赋值,name现在包含对NSString @“Test”的引用。但是,您可以决定使用copy或retain。不管您选择的是哪个版本的内存管理器,都隐藏了复杂性,您总是使用(或类似的)访问变量:
[self setName:@"Test"]
[self name]
Now setName:
might use assign/copy or retain
and you don't have to worry about it.
现在setName:可以使用assign/copy或retain,您不必担心它。
My guess is that iPhone tutorials use properties to make it easier for new developers to jump through memory management (even though it's handy to generate appropriate accessors with properties rather than implement them by hand every time).
我的猜测是,iPhone教程使用属性使新开发人员更容易进行内存管理(尽管用属性生成适当的访问器比每次手工实现更方便)。
#3
3
However, in the iPhone world, things seem to be different. People declare properties for every single instance variable, declare properties for
IBOutlets
, and use accessors/mutators to interact with instance variables within the class (e.g. they would write[self setName:@"Test"]
rather thanname = @"Test"
).然而,在iPhone世界里,事情似乎有所不同。人们为每个实例变量声明属性,为iboutlet声明属性,并使用访问器/mutators与类中的实例变量进行交互(例如,他们将写入[self setName:@"Test"],而不是name = @"Test")。
That's not iPhone-specific. Except in init
methods and the dealloc
method, it's good practice to always use your accessors. The main benefit, especially on the Mac (with Cocoa Bindings), is that using your accessors means free KVO notifications.
这不是于iphone。除了init方法和dealloc方法之外,最好始终使用访问器。主要的好处是,特别是在Mac上(带有Cocoa绑定),使用访问器意味着免费的KVO通知。
The reason why people “declare properties for every single instance variable” is most probably that all of their instance variables are things they want to expose as properties. If they had something they would want to keep private, they would not declare a property for it in the header file. (However, they may make a property for it in a class extension in the implementation file, in order to get the aforementioned free KVO notifications.)
人们“为每个实例变量声明属性”的原因很可能是他们所有的实例变量都是他们希望作为属性公开的东西。如果他们想要保持私有,他们不会在头文件中为它声明属性。(但是,他们可以在实现文件的类扩展名中为它创建一个属性,以便获得上述免费的KVO通知。)
Declaring properties for outlets is overkill, in my opinion. I don't see a point to it. If you don't make a property, the nib loader will set the outlet by direct instance-variable access, which is just fine for that task.
在我看来,为outlet声明属性有些过头了。我看不出有什么意义。如果不创建属性,nib加载程序将通过直接实例变量访问来设置outlet,这对该任务来说很好。
#4
2
I would suggest that modern development has made a very strong attempt to identify, define and apply best practices.
我认为,现代发展已经作出了非常有力的努力来确定、定义和应用最佳实践。
Among these best practices we find continuity and consistency.
在这些最佳实践中,我们发现了连续性和一致性。
Apart from arguing over use of accessors in init
and dealloc
methods, accessors should generally be used all the time (inside and outside of a class) for the benefits they offer, including encapsulation, polymorphic var implementations (which both allow for abstracting and refactoring) and to facilitate those best practices of continuity and consistency. The fundamental benefits of an object-orient language come into play when doing things in this way and exploiting the fullness of the language's capabilities. Always being consistent in one's coding is an oft undermentioned benefit, as any senior programmer will usually attest.
除了争论在init和dealloc方法,使用访问器访问器一般应使用所有的时间(一个类的内部和外部)他们提供的好处,包括封装、多态var(允许提取和重构)实现和促进这些最佳实践的连续性和一致性。面向对象语言的基本好处在以这种方式做事并充分利用语言的功能时发挥了作用。在一个人的编码中始终如一是一个经常被提及的好处,正如任何高级程序员通常会证明的那样。
#5
0
You can write like this
你可以这样写
//MyClass.h
@class Something;
@interface MyClass : NSObject
@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSArray *items;
@end
//MyClass.m
@interface MyClass()
@property (nonatomic, strong) IBOutlet NSTextField *myTextField;
@property (nonatomic, strong) Something *something;
@end