代码之家  ›  专栏  ›  技术社区  ›  Ariel Malka

什么会影响StringWithContentsOfFile返回的nsString的寿命?

  •  0
  • Ariel Malka  · 技术社区  · 16 年前

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

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

    NSString *path = [[NSBundle mainBundle] pathForResource:@"foo" ofType:@"txt"];
    NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path];
    NSData *data = [file readDataToEndOfFile];
    NSString *string = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding];
    [file closeFile];
    

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

    NSString *string; // CLASS VARIABLE
    (void) setupView
    {
      string = ...; // LOADING THE STRING
    }
    (void) drawView
    {
     ...;  // USING THE STRING
    }
    

    简而言之,它是一个基于nstimer的OpenGLES绘制循环。问题是字符串只能在第一帧访问。在下一帧,iPhone模拟器(2.2)在试图访问字符串时崩溃。

    可能有人会说,“在我的代码中,或者在我正在使用的OpenGLES代码中,有一些东西……但是,如何解释一个奇怪的事实,即如果我使用方法2加载字符串,那么一切都会按预期工作?

    有什么线索吗?

    2 回复  |  直到 16 年前
        1
  •  4
  •   Jason Coco superfell    16 年前

    在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可以使用 同种异体 消息。现在您拥有字符串对象,直到您在其他时间放弃所有权。考虑到您的特殊情况,这可能是您的最佳选择(也就是说,您不想使用方便构造函数,因为您希望字符串对象挂起以后使用)。

    选项2可以,因为您通过发送字符串 保持 . 在您的情况下,这可能不是最佳选择,因为 alloc/init 选项已经可用,通常更容易阅读。

    当您处理完一个对象并希望放弃该对象的所有权时,您将向该对象发送 release 消息。重要的是要记住,在可可中,发送一个物体 释放 信息并不意味着你要摧毁它,只是你要放弃所有权。

    Cocoa内存管理是围绕对象所有权的概念而设计的。虽然一开始可能有点混乱,但一旦你把你的头绕在它周围,它会使在环境中编程变得更容易,而不会引入内存错误、泄漏或其他错误。便利方法(比如 stringWithString )当你想要创建一个你只在短时间内使用的对象,并且只在一个函数或程序块的范围内使用的对象时,就可以使用它。如果您计划将对象保持在该范围之外,请使用 分配/初始化 新的 首选构造对象的方法。

    有关更多信息,请阅读 Memory Management Programming Guide for Cocoa . 对于Cocoa开发人员来说,它确实是必需的阅读。而且,它通常需要阅读、试验和阅读几次才能真正掌握,特别是如果你对其他记忆管理模式有很多经验的话。

        2
  •  1
  •   Pedro Henriques    16 年前

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