2
Line 1: First.h
Line 2: @property (nonatomic, retain) NSString *name;

Line  3: First.m
Line  4: @synthesize name;
Line  5: -(void)viewDidLoad()
Line  6: {
Line  7:     name = [NSString stringWithString:@"Hello"];
Line  8:                          OR
Line  9:     self.name = [[NSString alloc]initWithString:@"Hello"]; 
Line 10:                          OR
Line 11:  }
Line 12:-(void)dealloc()
Line 13: {
Line 14: [name release];
Line 14: } 

问题 1:
如果我遵循第 7 行,一切都很好,如果我使用第 9 行,则存在内存泄漏。据我所知, self 指向当前对象,如果我使用self.object或根本object没有区别。

问题2:如果我使用

@synthesize name = _name;

那么哪个是设置name的值,哪个是获取值呢?区别:

name = [NSString stringWithString:@"Hello"];
            OR
self.name = [NSString stringWithString:@"Hello"];
            OR
_name = [NSString stringWithString:@"Hello"];

问题 3:
如果我创建任何属性,是否需要在我分配的内存中分配显示内存泄漏?

4

3 回答 3

2

回答第一个问题:你得到了泄漏,因为用你保留创建的对象的方法初始化字符串,alloc但之后你没有释放对象,所以你得到了泄漏,同时用你创建了stringWithString一个自动释放的对象由自动释放池自动释放。请注意,在第 9 行的示例中,您正在初始化对象并将其传递给属性的设置器,如果您使用了 ivar ...

要回答您的第二个问题:您正在合成属性名称并将其关联到名为的内部变量(ivar)_name,因此在您的类内部,您可以使用 ivar 访问属性的值_name

我强烈建议阅读有关内存管理的 Apple 文档

于 2012-10-13T07:18:58.193 回答
2

问题 1:如果我遵循第 7 行,一切都很好,如果我使用第 9 行,则存在内存泄漏。据我所知, self 指向当前对象,如果我使用 self.object 或只是 object 没有更多区别。

Line  7:     name = [NSString stringWithString:@"Hello"];
Line  8:                          OR
Line  9:     self.name = [[NSString alloc]initWithString:@"Hello"]; 

在第 7 行,您使用了一个方便的构造函数,它返回一个自动释放的对象并将该对象直接分配给您的nameivar;现在,可以将一个自动释放的对象分配给一个保留属性,但是将一个自动释放的对象直接分配给一个 ivar 而不显式保留它是不正确的:

name = [[NSString stringWithString:@"Hello"] retain];

在第 9 行,您使用了 alloc/init,它为您提供了一个保留对象:将此类对象直接分配给 ivar 是正确的,但您应该在分配给保留属性之前自动释放它,例如:

self.name = [[[NSString alloc]initWithString:@"Hello"] autorelease]; 

您可以根据对象保留计数对此进行推理:

  1. 便利的构造函数会将保留计数设置为 1,但稍后将release通过框架完成的调用自动减少;

  2. alloc/init 将为您提供 1 的保留计数,除非您明确调用,否则不会减少release

  3. 当对象保留计数变为 0 时,它将被释放。

保留计数方面的推理只是查看整个内存管理问题并了解框架深处发生了什么的一种方式;不过,在任何情况下,这都不是分析对象生命周期的正确方法。

那么哪个用于设置名称的值,哪个用于获取值?name = [NSString stringWithString:@"Hello"];OR self.name = [NSString stringWithString:@"Hello"];OR之间的区别_name = [NSString stringWithString:@"Hello"];

name = [NSString stringWithString:@"Hello"];

_name = [NSString stringWithString:@"Hello"];

在给定的两种情况下都是一样的。这将绕过属性 setter(/getter) 方法并直接分配给 ivar。在这种情况下,您的应用程序迟早会崩溃,因为您将自动释放的对象直接分配给 ivar。这是正确的:

_name = [[NSString stringWithString:@"Hello"] retain];

或者

_name = [[NSString alloc] initWithString:@"Hello"];

请注意,在您将 ivar 声明为的程序中_name,您不能使用name来引用它;如果您只声明属性而不像问题 1 那样明确指定ivar,则可以使用name直接引用 ivar (在这种情况下,编译器会为您自动生成 ivar)。name

另一方面:

self.name = [NSString stringWithString:@"Hello"]; 

将使用属性访问器方法(实际上是 setter);由于您的属性被声明为retain,因此可以将便捷构造函数返回的自动释放变量分配给它stringWithString:

问题 3:如果我创建任何属性,是否需要在内存中分配,因为我分配显示内存泄漏。

这对我来说不是很清楚。

一份关于内存管理基础的好文档是:内存管理策略以及Apple 的高级内存管理编程指南中的实用内存管理

于 2012-10-13T07:22:47.410 回答
0

首先是一些背景知识,仅总结MRC的概念:

内存管理与所有权有关;只要您拥有一个对象,它就会存在,在您放弃所有权一段时间后,该对象将被销毁。您维护的对对象的任何引用实际上都是无效的,一旦您放弃所有权,就不应使用。

所有权不是独占的,而是遵循共享模型,在任何给定时间都可以有多个所有者,并且只有当一个对象没有所有者时,它才可以被销毁。

如果您只需要临时使用一个对象,例如在单个代码块中,您并不总是需要获得所有权。这部分是所有权和放弃方式的结果;您可以请求稍后放弃所有权,而不是立即放弃所有权。

稍后发生在应用程序执行的某些点,除非手动添加任何此类点,否则在通过运行循环的每个循环执行之后都会有一个这样的点。

所有权是通过retain调用或调用返回您拥有的对象的方法来断言的 - 最常见的是alloc,但也copy有其他的。使用调用放弃所有权release;并在稍后通过调用autorelease.

问题一:

Line  7:     name = [NSString stringWithString:@"Hello"];
Line  8:                          OR
Line  9:     self.name = [[NSString alloc] initWithString:@"Hello"]; 

第 7 行的右侧 (RHS) 返回对您拥有的对象的引用。左侧 (LHS) 将此引用分配给实例变量 name。您现在已经存储了对您不拥有的东西的引用,这很糟糕,因为将来该对象的所有者可能会放弃所有权,该对象已被销毁,并且您在name. 教训:*不要在实例变量中存储对您不拥有的对象的引用”。

另一方面,第 9 行的 RHS 返回对您拥有的对象的引用。然而,LHS 使用属性调用 self.name来存储引用,并且由于它是一个属性,它也具有所有权retain- 你现在拥有它两次,这很糟糕,但如果采用不同的方式;除非您还两次放弃所有权(您可能不会这样做),否则该对象将始终拥有所有者并且将永远存在,通常称为泄漏

如果您交换代码:

Line  7a:     name = [[NSString alloc] initWithString:@"Hello"];
Line  8a:                          OR
Line  9b:     self.name = [NSString stringWithString: @"Hello"]; 

然后它会做你所期望的。第 7a 行的 RHS 返回您拥有的对象引用,LHS 将其存储在由属性管理的实例变量 中。name name

第 9a 行的 RHS 返回一个您不拥有的对象引用,但是 LHS 使用属性调用,并且由于属性具有retain属性所有权,并且存储在实例变量 name中的引用指向拥有的对象。

在任何一种情况下,当当前实例 ( self) 被销毁时,因为属性name具有retain实例变量引用的任何对象的属性所有权,都name将被放弃。

问题2

使用有什么影响:

@synthesize name = _name;

这只是意味着该属性 name将使用实例变量 _name而不是name. 在您的代码片段中,您从不声明name,或者_name两者都由@synthesize;自动声明。所以只有一个name或一个_name实例变量取决于@synthesize. 所以问题 2 的答案就是问题 1 的答案,对实例变量的每个引用都name替换为_name.

问题 3

如果我理解这个问题,但我不确定我是否理解,则问题 1 的答案涵盖了它。

高温高压

于 2012-10-13T18:02:38.690 回答