0

我定义了以下变量:

@property (nonatomic, retain) NSMutableArray *arraySpeechSentences;

我正在尝试通过以下方式对其进行初始化:

// Set the array of sentences to the stored array
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
arraySpeechSentences = speechSentences;
[speechSentences release];

当我尝试调用 [arraySpeechSentences count] 时,应用程序崩溃。但是,如果我按以下方式设置变量:

// Set the array of sentences to the stored array
NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
self.arraySpeechSentences = speechSentences;
[speechSentences release];

我可以完美地调用 [arraySpeechSentences count]。我的印象是,如果你使用 self. 它只是检查变量是否已经设置,如果是,它将在分配新值之前释放对象。我是不是弄错了,如果是这样,我什么时候应该使用 self. 设定值?

感谢您的帮助,埃利奥特

4

3 回答 3

7

使用设置器(如self.foo = ...or [self setFoo:...])确实会释放旧值,但它也会保留新值,这在您给出的示例中是必需的。

问题是你正在分配和初始化你的数组,然后释放它。这表明您不再需要它。因此,您应该使用 setter(通常更可取)或不要释放您的数组。

于 2012-07-12T14:50:17.497 回答
3

如果您不使用 ARC,则应键入

arraySpeechSentences = [speechSentences retain];

因为您是直接访问实例变量,这意味着实例变量的值arraySpeechSentences将是speechSentence您刚刚释放的对象的地址,所以这是一个无效的指针。您在属性中声明的语义对实例变量本身没有影响。

键入self.arraySpeechSentences时,实际上是在使用 setter 的快捷方式[self setArraySpeechSentences:speechSentences],它实际上保留了作为参数传递的值(如果您合成了属性,则保留,因为您retain在属性声明中指定了;如果您自己编写访问器,则为您的工作,以确保您保留价值)。

于 2012-07-12T15:00:44.220 回答
2

我将尝试对此给出详细的答案。

首先,当您使用@property/@synthesize指令时,您会围绕变量创建 getter 和 setter 方法。

在您的情况下,变量被调用arraySpeechSentences(编译器将为您创建变量),您可以使用self..

self.arraySpeechSentences = // something 

是相同的

[self setArraySpeechSentences:something]; // setter

NSMutableArray* something = self.arraySpeechSentences;

等于

NSMutableArray* something = [self arraySpeechSentences]; // getter

在第一段代码中

NSMutableArray *speechSentences = [[NSMutableArray alloc] initWithArray:[tempDict objectForKey:key]];
arraySpeechSentences = speechSentences;

arraySpeechSentences指向同一个对象speechSentences指向。但是当你这样做时,你会[speechSentences release]释放那个对象,现在arraySpeechSentences是一个悬空指针。我想您会收到一条发送到已释放实例的消息。尝试让僵尸看到它。

就保留计数而言,当您这样做时,数组的保留计数为 1 alloc-init。但是当你release这样做时,保留计数变为零,对象不再存在,当你尝试访问时你会崩溃arraySpeechSentences

相反,当您处理属性时,应用于变量的策略很重要。由于属性使用retain策略,当您设置对象时

self.arraySpeechSentences = // something

被引用对象的保留计数增加。在引擎盖下,说self.arraySpeechSentences = // something等于调用 setter

- (void)setArraySpeechSentences:(NSMutableArray*)newValue
{
    // pseudo code here...
    if(newValue != arraySpeechSentences) {

       [arraySpeechSentences release];
       arraySpeechSentences = [newValue retain]; 
    }
}

第二个片段起作用,因为您的对象的保留计数在您执行时为 1 alloc-init,在您调用时变为 2,self.arraySpeechSentences =并在您执行释放时返回为 1。这一次,对象保持活动状态,因为它的保留计数为 1。

如果你有一个带有retainorcopy策略的属性,不要忘记在dealloclike 中释放对象,否则你可能会有泄漏。

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

要了解 Memory 的工作原理,我建议阅读MemoryManagement Apple 文档

PS从 iOS 5 开始,有一个新的编译器功能,称为ARC(自动引用计数),可以让您忘记retain/release调用。另外,由于它迫使您根据对象图进行思考,因此建议您看一下。

希望有帮助。

于 2012-07-12T15:14:46.273 回答