0

所以我正在尝试为 NSOperation 的子类编写一个初始化程序。这是我第一次使用 NSOperation。我的 NSOperation 子类如下所示:

.h
@property (nonatomic, copy) NSString *fileName;

.m
@synthesize fileName = _fileName;


- (id)initWitFileName:(NSString *)fileName  {
    if (self = [super init]) {
        _fileName = fileName;
    }
    return self;
}

- (void)dealloc {
    [_fileName release];
    [super dealloc];
}

- (void)main {
  // do long task
}

所以我想当我创建自己的初始化程序时,我应该自己设置 ivar,因为对象的状态在 init 方法中是不确定的。所以我不在初始化程序中使用访问器。当我的主要方法运行时,我得到一个内存错误访问和崩溃。但是,在我的 init 方法中,如果我这样做:

- (id)initWitFileName:(NSString *)fileName  {
        if (self = [super init]) {
            _fileName = [fileName retain];
        }
        return self;
    }

我没有崩溃。什么是正确的?我认为在第二种情况下我不会释放内存,因为访问器是(复制)。或者是因为我不使用访问器,所以我的 fileName 对象基本上只是因为 initWithFileName 方法中没有 +1 而被释放?谢谢!

4

3 回答 3

1

第二个很接近,但是:

- (id)initWitFileName:(NSString *)fileName  
{
    if (self = [super init]) {
        _fileName = [fileName copy];
    }
    return self;
}

更常见,因为NSString*属性通常用(nonatomic, copy).

NSMutableString这样做是为了避免调用者实际传递 a并随后更改值时出现问题或意外后果。

于 2012-07-27T01:12:33.277 回答
0

当您@synthesize具有一组属性时,您正在为对象生成 getter 和 setter。这允许您使用类似的方法

[self setFilename:@"MyFile.txt"]

或者

self.filename = @"MyFile.txt"

上面两行的功能完全相同,并且可以这样实现:

- (void)setFilename:(NSString *)string {
    _filename = [string copy];
    // Or, for a retained property:
    // _filename = [string retain];
}

这个实现被过度简化了。请参阅下面 idz 的评论,以更好地理解真正的 setter 将使用的逻辑。


在上面的示例中,您只是使用=运算符,而不是生成的函数。

_fileName = fileName;

因此,您只需将地址设置为_fileNameto fileName。您的所有synthesize属性都无关紧要,在这里也没有什么不同。

你的解释:

是不是因为我不使用访问器,所以我的 fileName 对象基本上只是因为 initWithFileName 方法中没有 +1 而被释放?

完全正确。要正确复制copy合成器使用的属性,请使用以下命令:

_fileName = [fileName copy];
于 2012-07-27T01:21:25.557 回答
0

想法 1:使用 ARC。在 ARC 中,您需要声明您的 ivar strong,然后使用合成的 setter 或直接分配 ivar。将为您添加保留,一切都会好起来的。

想法2:使用保留。如果由于某种原因您无法使用 ARC,为什么不将 NSString 声明为保留,而不是复制?保持不变事物的同一个实例是可以的。(共享一个可变的东西也是有用的,只要两个类都明白他们正在这样做)。

思路3:如果一定要用非arc,而且一定要用copy,把ivar设置成copy。这将通过复制来修复您的崩溃。就像现在一样,代码将句柄复制到传递的字符串,但不是它的内容。传递的字符串是dealloc'd,你的班级被僵尸卡住了。你可以说 _filename = [string copy]; 正如其他人所建议的那样。

作为旁注,调用 self = [super init]; 在重写的 init 方法中是正确的。由于您正在制作自己的 init 变体,我认为调用 self = [self init]; 更合适

于 2012-07-27T23:56:00.120 回答