Cocoa touch 什么会影响stringWithContentsOfFile“返回的NSString的寿命;?

Cocoa touch 什么会影响stringWithContentsOfFile“返回的NSString的寿命;?,cocoa-touch,string,file-access,Cocoa Touch,String,File Access,考虑以下两种从文件读取字符串的方法: NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"]; NSString *string = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL]; 我更愿意依赖方法#1,但在以下上下文中使用时,它的行为会很奇怪: NSString *stri

考虑以下两种从文件读取字符串的方法:

NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
NSString *string = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];

我更愿意依赖方法#1,但在以下上下文中使用时,它的行为会很奇怪:

NSString *string; // CLASS VARIABLE
(void) setupView
{
  string = ...; // LOADING THE STRING
}
(void) drawView
{
 ...;  // USING THE STRING
}
简而言之,它是一个基于NSTimer的OpenGL ES绘图循环。问题是字符串只能在第一帧访问。在下一帧,IPhone模拟器(2.2)在试图访问字符串时崩溃

可能“在我的代码中,或者在我正在使用的OpenGL ES代码中”有人会说。。。但如何解释一个奇怪的事实,即如果我使用方法2加载字符串,那么一切都会按预期进行


有什么线索吗?

当您使用类方法创建字符串时,通常会将其添加到最顶层的自动释放池中。在事件循环结束时,池向其持有的所有对象发送一条释放消息。在这种情况下,新创建的字符串的retain count等于1,在循环结束时达到0并被释放。如果要保留字符串,请在事件循环结束时向其发送retain消息以保持retain count为正值。

使用类方法创建字符串时,通常会将其添加到最顶层的自动释放池中。在事件循环结束时,池向其持有的所有对象发送一条释放消息。在这种情况下,新创建的字符串的retain count等于1,在循环结束时达到0并被释放。如果要保留字符串,请在事件循环结束时向其发送保留消息以保持保留计数为正值。

在Cocoa中,只有使用
alloc
new
copy
retain
创建对象时,您才拥有该对象。当您不拥有某个对象时,您无法保证该对象在您使用它的本地范围之外。在您的示例中,由于您没有使用上述任何方法创建新字符串,因此无法保证如果存储它,它以后会出现

为了获得您尚未拥有的对象的所有权(即,您希望它保留下来以便以后使用),您必须向该对象发送一条保留消息。例如,如果您按照如下所示重写代码,您将拥有该字符串,并且不必担心以后使用它:

// option 1
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
NSString *string = [[NSString alloc] initWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];

// option 2
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
NSString *string = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];
[string retain];
选项1没有问题,因为您专门使用
alloc
消息创建字符串。现在您拥有字符串对象,直到您在其他时间放弃所有权为止。考虑到您的特殊情况,这可能是最好的选择(例如,您并不真的想使用方便的构造函数,因为您希望字符串对象挂起以供以后使用)

选项2没有问题,因为您通过发送
retain
来获得字符串的所有权。在您的情况下,这可能不是最好的选择,因为已经有一个
alloc/init
选项可用,而且通常更容易阅读

当您处理完某个对象并希望放弃该对象的所有权时,您会向该对象发送
释放
消息。重要的是要记住,在Cocoa中,向对象发送
release
消息并不意味着您正在销毁它,只是意味着您正在放弃所有权

Cocoa内存管理是围绕对象所有权的思想设计的。虽然一开始可能会有点困惑,但一旦你仔细考虑了它,它会使在环境中编程变得更加容易,而不会引入内存错误、泄漏或其他bug。方便方法(如
stringWithString
)的设计目的是,当您想要创建一个只在一个函数或程序块的范围内使用很短时间的对象时,可以使用它。如果计划将对象保留在该范围之外,则首选使用
alloc/init
new
方法来构造对象


有关更多信息,请阅读。它确实被认为是Cocoa开发人员的必读书籍。此外,通常需要阅读、实验和再读几遍才能真正掌握它,特别是如果你对其他内存管理模型有很多经验。

在Cocoa中,只有使用
alloc
new
copy
retain
创建对象时,你才拥有它。当您不拥有某个对象时,您无法保证该对象在您使用它的本地范围之外。在您的示例中,由于您没有使用上述任何方法创建新字符串,因此无法保证如果存储它,它以后会出现

为了获得您尚未拥有的对象的所有权(即,您希望它保留下来以便以后使用),您必须向该对象发送一条保留消息。例如,如果您按照如下所示重写代码,您将拥有该字符串,并且不必担心以后使用它:

// option 1
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
NSString *string = [[NSString alloc] initWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];

// option 2
NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
NSString *string = [NSString stringWithContentsOfFile:path encoding:NSASCIIStringEncoding error:NULL];
[string retain];
选项1没有问题,因为您专门使用
alloc
消息创建字符串。现在您拥有字符串对象,直到您在其他时间放弃所有权为止。考虑到您的特殊情况,这可能是最好的选择(例如,您并不真的想使用方便的构造函数,因为您希望字符串对象挂起以供以后使用)

选项2没有问题,因为您通过发送
retain
来获得字符串的所有权。在您的情况下,这可能不是最好的选择,因为已经有一个
alloc/init
选项可用,而且通常更容易阅读

当您处理完一个对象并想要放弃该对象的所有权时,您将向该对象发送
relea