假设我的班级myPropertyName
中定义了一个名为MyClassName
的媒体资源。本文中使用了手动内存管理。
MyClassName.h
#import <UIKit/UIKit.h>
@interface MyClassName : NSObject {
@private
NSObject* myPropertyName;
@public
}
@property (nonatomic, retain) NSObject* myPropertyName;
// Some methods prototypes are here
@end
MyClassName.m
#import "MyClassName.h"
@implementation MyClassName
@synthesize myPropertyName;
// Some methods are here
@end
我对诸如myPropertyName
声明的位置,它与实例变量之间的区别等用法感到困惑。例如,这三个初始化代码语句之间的区别是什么,例如,在我的类-(void)init
的自定义myClassName
方法中。
self.myPropertyName = [[[NSObject alloc] init] autorelease];
这个是调用myPropertyName
setter,但是我不确定setter中使用的实例变量的名称是什么,myPropertyName
(因为我已经声明了一个名为@private的字段myPropertyName
)或_myPropertyName
(有人说这个带有下划线的是默认设置)?
myPropertyName = [[NSObject alloc] init];
这会初始化myPropertyName
属性的实例变量吗?如果我没有@synthesize myPropertyName = _myPropertyName;
,那么它是错的,因为该属性的默认实例变量被称为_myPropertyName
。
_myPropertyName = [[NSObject alloc] init];
即使我使用_myPropertyName
和myPropertyName
,@synthesize myPropertyName;
仍被声明为我的媒体资源@private NSObject* myPropertyName;
的实例变量吗?
根据我的理解,属性只是一个名称(例如myPropertyName
),应该有一些封装的实例变量用于代码中的实际操作,例如赋值。
答案 0 :(得分:2)
首先,我强烈推荐阅读由{nhgrif链接的Apple's documentation on properties。但是,我理解文档可能是一个有点密集的阅读材料(虽然Apple发现,并不是那么糟糕),所以我将在这里简要介绍一下属性。
我喜欢这样的例子,所以我要用更新的形式重写你的两个类。
<强> MyClassName.h 强>
#import <UIKit/UIKit.h>
@interface MyClassName : NSObject
@property (nonatomic, strong) NSObject *myPropertyName;
// method prototypes here
@end
<强> MyClassName.m 强>
#import "MyClassName.h"
@implementation MyClassName
// some methods here
@end
班级MyClassName
现在有一个名为myPropertyName
的{{1}}类型的属性。编译器将为你做很多工作&#34; free&#34;在这种情况下。具体来说,它将生成一个支持变量,并为NSObject *
生成一个setter和getter。如果我要重写这两个文件,假装我编译器,包括那些东西,它们看起来像这样:
<强> MyClassName.h 强>
myPropertyName
<强> MyClassName.m 强>
#import <UIKit/UIKit.h>
@interface MyClassName : NSObject {
NSObject *_myPropertyName;
}
@property (nonatomic, strong) NSObject *myPropertyName;
- (void)setMyPropertyName:(NSObject *)obj;
- (NSObject *)myPropertyName;
@end
同样,所有这一切都发生在&#34;免费&#34;:我只是告诉你幕后发生了什么。现在为你编号的问题。
#import "MyClassName.h"
@implementation MyClassName
- (void)setMyPropertyName:(NSObject *)obj
{
_myPropertyName = obj;
}
- (NSObject *)myPropertyName
{
return _myPropertyName;
}
@end
首先,您可能应该使用自动引用计数或ARC。如果是,您将无法致电self.myPropertyName = [[[NSObject alloc] init] autorelease];
。忽略那部分,这很好。排除autorelease
,这完全等同于:
[self setMyPropertyName:[[NSObject alloc] init]];
如果你看一下我上面写的第二个autorelease
文件,基本上会转换为:
`_myPropertyName = [[NSObject alloc] init];
.m
如上所述,此代码将给出编译器错误,因为此类中没有名为myPropertyName = [[NSObject alloc] init];
的变量。如果您真的想要访问基础(或者&#34;支持&#34;)myPropertyName
属性的实例变量,您可以使用其真实姓名:
myPropertyName
但大多数情况下,使用setter会更好,如第1点所示,因为它允许副作用,键值编码和其他好东西。
_myPropertyName = [[NSObject alloc] init]; // note the underscore
喔。嗯,你明白了。见第2点。
你提到过:
我对诸如
_myPropertyName = [[NSObject alloc] init];
声明的位置,它在实例变量之间的区别等用法感到困惑。例如,这三个初始化代码语句之间的区别是什么,例如,在我的类myPropertyName
的自定义-(void)init
方法中。
如果没有明确表示,财产是一种抽象的概念;其数据存储在通常由编译器分配的普通实例变量中。它的访问通常应限于setter和getter,但有一些重要的例外。为了简短地回答这个问题,我不会详细介绍。
还有一件事:正如nhgrif所提到的,您不再需要使用myClassName
关键字了。现在编译器已经隐含地理解了这一点。
如果您对此不确定,请发表评论,或者更好的是阅读docs。
答案 1 :(得分:1)
我们来看这个例子:
@property NSString *fullName;
如果在实现中,我们覆盖了setter和getter,并且在这些setter和getter中,我们不使用实例变量fullName
,它永远不会被创建。例如:
- (NSString *)fullName
{
return [NSString stringWithFormat:@"%@ %@", self.firstName, self.lastName];
}
- (void)setFullName:(NSString *)fullName
{
//logic to split fullName into two strings
//self.firstName = etc
//self.lastName = etc.
}
在此示例中,没有创建fullName
的实例变量。
根据Apple's Official Documentation
但是,如果不覆盖setter和getter,则会创建一个实例变量。
作为旁注,您可以声明属性readonly
,然后简单地覆盖getter
(不使用变量)将阻止创建ivar
。同样,您可以声明属性writeonly
,然后覆盖setter
。