【问题标题】:Property in Objective-CObjective-C 中的属性
【发布时间】:2012-10-13 07:13:43
【问题描述】:
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:
如果我创建任何属性,是否需要在分配的内存中分配显示内存泄漏?

【问题讨论】:

  • 请使用 ARC——不要使用手动内存管理。
  • 但我刚开始使用 iOS,所以需要了解内存管理主题。
  • 如果您想了解内存管理,唯一要做的就是阅读 Apple 的相关文档。真的没有替代品,对不起。 :)

标签: ios objective-c memory-management synthesize


【解决方案1】:

问题 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 行,您使用了一个方便的构造函数,该构造函数返回一个自动释放的对象并将该对象直接分配给您的name ivar;现在,可以将自动释放的对象分配给保留属性,但将自动释放的对象直接分配给 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的值,哪一个是用来取值的呢? name = [NSString stringWithString:@"Hello"];self.name = [NSString stringWithString:@"Hello"];_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 来引用它;如果您声明 only 属性而不像问题 1 那样明确指定 ivar,则可以使用 name 直接引用 ivar(在这种情况下,name 将是自动生成的 ivar由编译器为你)。

另一方面:

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

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

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

这对我来说不是很清楚。

有关内存管理基础知识的好文档是:Memory Management Policy 和 Apple 的高级内存管理编程指南中的 Practical Memory Management

【讨论】:

  • @sergio - 不幸的是,我认为这个答案是错误的。例如。第 7 行一个非拥有的引用被存储在一个没有所有权的实例变量中 - 所以这一行是 wrong 并且不像答案所暗示的那样好。我添加了一个答案来解释这一点。
  • @CRD:感谢您指出这一点。我已经扩展了我的答案并完整描述了这两种情况(第 7 行和第 9 行)发生的情况。
【解决方案2】:

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

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

我强烈建议阅读Apple documentation about memory management

【讨论】:

  • 表示 _name 现在可以用于设置并获取对象的值。
【解决方案3】:

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

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

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

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

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

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

问题 1:

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 将其存储在 instance 变量 name 中,由 property name 管理。

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

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

问题 2

使用有什么影响:

@synthesize name = _name;

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

问题 3

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

HTH

【讨论】:

    猜你喜欢
    • 2011-06-10
    • 2019-02-21
    • 1970-01-01
    • 2011-08-08
    • 2011-06-02
    • 2011-08-04
    • 1970-01-01
    • 2012-09-05
    • 2011-05-06
    相关资源
    最近更新 更多