【问题标题】:Why can I not initialise my variable without using self为什么我不能在不使用 self 的情况下初始化我的变量
【发布时间】:2012-07-12 08:36:24
【问题描述】:

我定义了以下变量:

@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.设置值?

感谢您的帮助, 艾略特

【问题讨论】:

  • 在处理属性时始终使用 self.propertyName。并在 dealloc 中以相同的方式将它们归零。
  • 你的问题的第一行可能已经出现了混淆:当你使用@property时,你没有声明一个变量,而是一个属性。因此需要self,实例本身内的所有属性访问都需要它。
  • @TeodorCarstea 除非您覆盖 setXXX 方法,在这种情况下您应该访问底层实例变量(并自己处理保留)
  • 请参阅我的answer 到上一个问题,这可能有助于您理解@property@synthesize

标签: iphone objective-c ios


【解决方案1】:

我会尽量给出详细的答案。

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

在您的情况下,该变量称为 arraySpeechSentences(编译器将为您创建变量),您可以使用 self. 访问这些方法(setter 和 getter)。

self.arraySpeechSentences = // something 

相同
[self setArraySpeechSentences:something]; // setter

NSMutableArray* something = self.arraySpeechSentences;

等于

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

在代码的第一个sn-p中

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

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

就保留计数而言,当您执行alloc-init 时,数组的保留计数为 1。 但是当你 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]; 
    }
}

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

如果您有一个带有retaincopy 策略的属性,请不要忘记释放dealloc 中的对象,否则可能会发生泄漏。

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

要了解内存的工作原理,我建议阅读MemoryManagement Apple doc

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

希望对您有所帮助。

【讨论】:

  • 非常感谢您的详细回答,现在更有意义了。我认为变量声明中的保留也会自动保留它设置为指向的任何对象。
【解决方案2】:

如果你没有使用 ARC,你应该输入

arraySpeechSentences = [speechSentences retain];

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

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

【讨论】:

  • 感谢您的信息,我错误地认为声明中的保留会自动执行此操作。
【解决方案3】:

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

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

【讨论】:

  • 感谢您的回答,现在说得通了。尽管您的评价最高,但我为 Flex 提供了详细信息的答案,但我感谢您的帮助!
  • 不客气!他当然包含了很多的细节。 :)
猜你喜欢
  • 2015-05-16
  • 2011-05-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-07
  • 2020-09-02
  • 2010-12-16
  • 2020-08-01
相关资源
最近更新 更多