Iphone 获取构造函数中的属性集

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

我是Objective-C的新手。我试图在构造函数中获取属性集,但遇到EXC_BAD_访问错误。这是我的构造函数:

- (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