【问题标题】:Need assistance regarding NSString需要有关 NSString 的帮助
【发布时间】:2015-06-23 19:59:13
【问题描述】:

在 NSString NSString Class Reference 这意味着什么

Distributed objects:
Over distributed-object connections, mutable string objects are passed by-reference and immutable string objects are passed by-copy.

而且 NSString 无法更改,所以当我在此代码中更改 str 时会发生什么

NSString *str = @"";
for (int i=0; i<1000; i++) {
    str = [str stringByAppendingFormat:@"%d", i];
}

我会出现内存泄漏吗?还是什么?

【问题讨论】:

  • 不,您的代码不会出现内存泄漏。
  • 如果 str 获得新副本,那么旧副本将没有引用,所以我没有出现内存泄漏吗?
  • 不,因为你没有保留那个对象,它是用方便的方法创建的,你不拥有它,将在下一个自动释放池周期释放。
  • @FahriAzimov 但如果我使用非 ARC 会怎样
  • 如果你不使用 ARC,你会得到你应得的。

标签: ios objective-c nsstring


【解决方案1】:

不,您的代码不会发生内存泄漏,因为您没有在循环中保留这些对象,它们是使用便捷方法创建的,您不拥有它们,它们将在下一个周期释放自动释放池。而且,无论您是否使用 ARC,使用便捷方法创建且未保留的对象都将被释放,无论它们是否超出其上下文。

【讨论】:

    【解决方案2】:

    您的代码在做什么:

    NSString *str = @""; // pointer str points at memory address 123 for example
    for (int i=0; i<1000; i++) {
        // now you don't change the value to which the pointer str points
        // instead you create a new string located at address, lets say, 900 and let the pointer str know to point at address 900 instead of 123
        str = [str stringByAppendingFormat:@"%d", i]; // this method creates a new string and returns a pointer to the new string! 
    
        // you can't do this because str is immutable
        // [str appendString:@"mmmm"];
    }
    

    可变意味着您可以更改 NSString。例如使用 appendString。

    pass by copy意味着你得到了一份NSString的拷贝,你可以为所欲为;它不会改变原来的 NSString

    - (void)magic:(NSString *)string
    {
        string = @"LOL";
        NSLog(@"%@", string);
    }
    
    // somewhere in your code
    NSString *s = @"Hello";
    NSLog(@"%@", s); // prints hello
    [self magic:s];  // prints LOL
    NSLog(@"%@", s); // prints hello not lol
    

    但是假设你得到一个可变的 NSString。

    - (void)magic2:(NSMutableString *)string
    {
        [string appendString:@".COM"];
    }
    
    // somewhere in your code
    NSString *s = @"Hello";
    NSMutableString *m = [s mutableCopy];
    NSLog(@"%@", m); // prints hello
    [self magic2:m];
    NSLog(@"%@", m); // prints hello.COM
    

    因为您传递了引用,您实际上可以更改字符串对象的“值”,因为您使用的是原始版本而不是重复版本。

    注意 只要您的应用程序存在,字符串文字就会存在。在您的示例中,这意味着您的 NSString *str = @""; 永远不会被释放。所以最后在你遍历你的 for 循环之后,你的记忆中有两个字符串对象。它的@"" 您无法再访问它,因为您没有指向它的指针,但它仍然存在!而你的新字符串 str=123456....1000;但这不是内存泄漏。

    more information

    【讨论】:

    • 如果 str 获得新副本,那么旧副本将没有引用,所以我没有出现内存泄漏吗?
    • 否,因为您的旧字符串将被删除。只要你的“for循环”没有更进一步,你的旧字符串就会存在。
    • 但是如果我使用的是非 ARC。
    • 对不起,我弄错了。只要您的应用程序存在,像 NSString *s = @"string" 这样的字符串文字就会存在!我编辑了我的答案。
    • 如果我不能再访问一个对象意味着我失去了它的引用,为什么它不是内存泄漏?
    【解决方案3】:

    您不会在示例代码中遇到内存泄漏,因为自动引用计数会检测到 str 的分配并(自动)释放旧的 str。

    但是这样做会更好的编码风格(并且几乎可以肯定更好的性能):

    NSMutableString* mstr = [NSMutableString new];
    for(int i = 0; i < 1000; ++i){
        [mstr appendFormat:@"%d",i];
    }
    NSString* str = mstr;
    ...
    

    关于第一个问题,我认为这意味着远程进程对可变字符串所做的更改将反映在原始进程的对象中。

    【讨论】:

    • 如果 str 获得新副本,那么旧副本将没有引用,所以我没有出现内存泄漏吗?
    【解决方案4】:

    In 不会泄漏内存,但会获得更多的内存分配,因为创建了不可变副本的新副本,因为时间循环触发器[str stringByAppendingFormat:@"%d", i];

    当您将数据未引用或孤立时,将执行内存泄漏,这不会在每次循环时使您的最后一个字符串孤立副本,但会在操作完成时清除NSString 的所有副本,或者@ 987654323@.

    【讨论】:

    • 如果 str 获得新副本,那么旧副本将没有引用,所以我没有出现内存泄漏吗?