Iphone 获取构造函数中的属性集
我是Objective-C的新手。我试图在构造函数中获取属性集,但遇到EXC_BAD_访问错误。这是我的构造函数:Iphone 获取构造函数中的属性集,iphone,objective-c,ios,Iphone,Objective C,Ios,我是Objective-C的新手。我试图在构造函数中获取属性集,但遇到EXC_BAD_访问错误。这是我的构造函数: - (id) init { self = [super init]; if (self != nil) { appFolderPath = [[NSBundle mainBundle] resourcePath]; fileManager = [NSFileManager defaultManager]; mediaArray = [fileMan
- (id) init {
self = [super init];
if (self != nil) {
appFolderPath = [[NSBundle mainBundle] resourcePath];
fileManager = [NSFileManager defaultManager];
mediaArray = [fileManager directoryContentsAtPath: [appFolderPath stringByAppendingString:@"/Media/Silly"]];
mediaIndex = 0;
}
return self;
}
以下是我的财产:
@property (retain) NSFileManager* fileManager;
@property (retain) NSString* appFolderPath;
@property int mediaIndex;
@property (retain) NSArray* mediaArray;
有什么想法吗?您的属性上有retain关键字,这很好。但是,这并不重要,因为你实际上并没有使用它们。您直接访问IVAR,绕过Objective-c编译器为您生成的getter方法 要在和ivar与属性之间进行对比,请参见以下代码: MyInterface.h
@interface MyInterface : NSObject {
@private
NSFileManager * fileManager; // This is an instance variable, or 'ivar'
}
@property (retain) NSFileManager * fileManager; // This is the declaration of a property
MyInterface.m
@implementation MyInterface {
@synthesize fileManager;
// Calling this causes the Objective-C compiler to generate the following
// methods for you:
// -(NSFileManager *) getFileManager ...
// and - (void) setFileManager: (NSFileManager *) val ...
}
要使用类中的ivar,您只需引用其名称,在您的示例中,您使用以下行:
fileManager = [NSFileManager defaultManager];
由于调用的方法返回的自动释放实例未被保留,因此稍后在程序中会出现EXEC\u BAD\u访问异常。要使用该属性,需要在其前面加上所属对象引用:
self.fileManager = [NSFileManager defaultManager];
这可确保您的ivar设置为并保留
编辑 现在,为了真正理解实例变量和属性之间的区别,您可以将接口声明为:
@interface MyInterface : NSObject {
@private
NSFileManager * _fileManager;
}
@property (retain) NSFileManager * fileManager;
在你的.m中,你会:
@综合文件管理器=\u文件管理器
现在,当您尝试执行
fileManager=[NSFileManager defaultManager]代码>您的代码不会编译,因为您的类中没有名为fileManager
的ivar。这是一种很有用的编码方式,可以避免常见错误。您的属性上有retain关键字,这很好。但是,这并不重要,因为你实际上并没有使用它们。您直接访问IVAR,绕过Objective-c编译器为您生成的getter方法
要在和ivar与属性之间进行对比,请参见以下代码:
MyInterface.h
@interface MyInterface : NSObject {
@private
NSFileManager * fileManager; // This is an instance variable, or 'ivar'
}
@property (retain) NSFileManager * fileManager; // This is the declaration of a property
MyInterface.m
@implementation MyInterface {
@synthesize fileManager;
// Calling this causes the Objective-C compiler to generate the following
// methods for you:
// -(NSFileManager *) getFileManager ...
// and - (void) setFileManager: (NSFileManager *) val ...
}
要使用类中的ivar,您只需引用其名称,在您的示例中,您使用以下行:
fileManager = [NSFileManager defaultManager];
由于调用的方法返回的自动释放实例未被保留,因此稍后在程序中会出现EXEC\u BAD\u访问异常。要使用该属性,需要在其前面加上所属对象引用:
self.fileManager = [NSFileManager defaultManager];
这可确保您的ivar设置为并保留
编辑
现在,为了真正理解实例变量和属性之间的区别,您可以将接口声明为:
@interface MyInterface : NSObject {
@private
NSFileManager * _fileManager;
}
@property (retain) NSFileManager * fileManager;
在你的.m中,你会:
@综合文件管理器=\u文件管理器
现在,当您尝试执行fileManager=[NSFileManager defaultManager]代码>您的代码不会编译,因为您的类中没有名为fileManager
的ivar。这是一种很有用的编码方式,可以避免常见错误。您不是在为属性赋值,而是在为实例变量赋值。如果要使用这些属性,需要在名称前面加上self.
,如self.fileManager
中所示
结果是这些对象不会被保留,以后可能会被解除分配。当您稍后尝试访问属性(或其实例变量)时,对象已经消失。有时在他们的位置上有不同的物体,有时是垃圾。这就是崩溃的原因。您没有分配给属性,而是分配给实例变量。如果要使用这些属性,需要在名称前面加上self.
,如self.fileManager
中所示
结果是这些对象不会被保留,以后可能会被解除分配。当您稍后尝试访问属性(或其实例变量)时,对象已经消失。有时在他们的位置上有不同的物体,有时是垃圾。那就是你发生车祸的时候。@Perception已经解释了为什么这不起作用的细节。下面是如何纠正这个问题。由于您没有使用发送retain消息的合成setter,因此在直接访问实例变量时,您必须自己处理它。还要注意,类型为NSString
的对象应该被复制而不是保留,因此appFolderPath
的声明实际上应该是@property(非原子,复制)NSString*appFolderPath代码>。考虑到所有这些因素,您的-init
应该如下所示
- (id)init
{
self = [super init];
if (self != nil)
{
appFolderPath = [[NSBundle mainBundle] resourcePath] copy];
fileManager = [NSFileManager defaultManager] retain];
mediaArray = [fileManager directoryContentsAtPath:[appFolderPath stringByAppendingString:@"/Media/Silly"]] retain];
mediaIndex = 0;
}
return self;
}
@Perception已经解释了为什么这不起作用的来龙去脉。下面是如何纠正这个问题。由于您没有使用发送retain消息的合成setter,因此在直接访问实例变量时,您必须自己处理它。还要注意,类型为NSString
的对象应该被复制而不是保留,因此appFolderPath
的声明实际上应该是@property(非原子,复制)NSString*appFolderPath代码>。考虑到所有这些因素,您的-init
应该如下所示
- (id)init
{
self = [super init];
if (self != nil)
{
appFolderPath = [[NSBundle mainBundle] resourcePath] copy];
fileManager = [NSFileManager defaultManager] retain];
mediaArray = [fileManager directoryContentsAtPath:[appFolderPath stringByAppendingString:@"/Media/Silly"]] retain];
mediaIndex = 0;
}
return self;
}
我不想冒险-@Perception提供了一个彻底的解释,然后@Mark给出了实际的解决方案
以下是快速版本:
这个
和匹配
@synthesize appFolderPath = _appFolderPath;
表示编译器生成以下方法
- (void)setAppFolderPath(NSString *)appFolderPath;
- (NSString *)appFolderPath;
根据您选择的选项retain/copy/assign
,这些方法将负责分配时保留/复制/引用对象的内存管理。此内存管理仅在使用时生效
[self setAppFolderPath:@"My Folder Path"];
或
现在,这对于类中的一般使用都是很好的,但有时建议不要使用getter和setter,以防它们引起副作用。通常要避免使用getter和setter的两个地方是init
方法和dealloc
因此,在init
方法中,应该直接访问ivar,而不使用getter/setter。T