【问题标题】:The final word on NSStrings: Mutable and Immutable关于 NSStrings 的最后一句话:可变和不可变
【发布时间】:2010-10-28 16:05:27
【问题描述】:

我已经阅读了几本书......以及在线......关于不可变和可变字符串的内容。 他们声称“不可变字符串”无法更改。 (但他们从不定义“改变”。)

哪些 NSString 可以在不使用 NSMutableString 的情况下进行更改?

字符串包含“catfish”...我稍后尝试将其更改为“cat”。 (相同的字母,只是更短。)

它包含“cat”...我尝试将其更改为“catfish”。 (类似的开始......但只是变长了。)

我把“猫”改成“猫”。 (相同的字母,但只是大小写有所不同。)

我把“猫”改成了“狗”。 (完全不同的字符串,但长度相同。)

我把“猫”改成了“山茱萸”。 (完全不同的字符串,但更长。)

【问题讨论】:

  • 几乎是克林顿式的问题!

标签: objective-c cocoa cocoa-touch immutability mutable


【解决方案1】:

答案是 - 没有。不可变意味着它不能更改为与原始字符串不同的任何东西。每个字符都保持不变,长度不能改变,等等。一旦它被定义,你就不能改变关于该字符串的任何内容。如果你想让它更长或更短或更改任何字符,你需要创建一个新字符串(或使用 NSMutableString 开头)。

【讨论】:

  • 感谢您的快速回复。这不是让 NSString 毫无用处吗?我将 VARIABLE 设置为 NSString 值...然后我永远无法更改它。这不是在其他语言中通常称为“常数”吗?我会(相反)99% 的时间都想用我的刺“做点什么”。那么我不应该在几乎所有地方都使用 MSMutableString 吗? (但我很少看到它被使用,与非常常用的 NSString 相比。)
  • 想象一下如果 int/float/long 也是不可变的。诠释 x = 5;然后 x 可以永远被更改。不可变是(几乎)无用的。没有?
  • “做某事”可能只是意味着从某些数据存储中读取它们并显示它们。在这种情况下,您不需要修改它们。
  • @BettyT:您将对象的不变性与分配给指向对象的变量的能力混淆了。如果对象没有允许更改其状态的方法,则该对象是不可变的。如果您将变量设置为指向不可变对象,您仍然可以随时将该变量设置为指向任何其他对象。对象是不可变的意味着你知道一旦你指向一个对象,它的状态就不会以某种方式改变(例如,其他人也有一个指向同一个对象的变量)。附言NSNumber 对象也是不可变的,但不是没用的。
  • 为了扩展newacct 的评论,在Objective-C 中区分变量和对象是非常重要的。任意数量的变量都可以指向同一个对象。这些变量中的任何一个都可以在以后重新分配给新对象,而不会影响其他任何变量。另一方面,如果对象本身发生了变异,那么代码中每个带有指向该对象的变量的地方都可以看到该对象的变化。像这样从你下面换掉一个物体通常是不可取的。
【解决方案2】:

如果我声明一个变量:

NSString * var;
// Here some code giving a new value to var

不可变的是var指向的对象,而不是var本身。

这意味着我无法更改var 指向的对象的任何内容,但我可以更改指向的对象。

var 上不允许您提到的任何操作,但您可以将 var 分配给另一个不同的字符串:

NSString * anotherVar;
// Here some code giving a new value to anotherVar

var = anotherVar; // This is allowed (with a memory leak if GC is disabled)

// The following is also allowed: -stringWithFormat: creates a new object
var = [var stringWithFormat:@"%@ with more chars", var];

【讨论】:

  • 请注意,该代码应该在禁用 GC 的情况下导致内存泄漏。你正在做的是一个简单的任务,不涉及 -retain 或 -copy 。因此,没有内存泄漏。此外,您的字符串格式应该是 @"%@ with more chars",因为 %s 仅适用于 C 字符串,我相信。
  • 谢谢,我已经更新了格式。关于内存泄漏,这取决于 var 的第一个值是如何创建的。
【解决方案3】:

NSString 不能被编辑,每次你为 NSString 对象分配一个字符串值时,它都会孤立旧的字符串对象并重新创建新的字符串对象。如果您正在处理大型字符串缓冲区,那将是一项昂贵的操作。如果您正在处理大型字符串缓冲区,请使用 NSMutableString 以获得最佳性能。这类似于 .net 中的 string vs stringBuilder。

【讨论】:

    【解决方案4】:

    你也需要定义“改变”:)

    基本上,当您创建一个 NSString 时,您正在创建一个字符数组,并且您告诉编译器 所述数组的内容永远不会改变。 “永不改变”部分是“不可变”部分;字符串包含的数据永远无法修改。

    另一方面,NSMutableString 允许您实际更改它指向的数据(因此它是“可变的”)。注意 NSMutableString 存在的 'appendString' 方法;这实际上需要数据并将其拍到字符串的末尾。

    例如,如果您有:

    NSString *myString = @"Cat"; myString = @"金鱼";

    这样就可以了。您永远不会真正更改 myString 包含的数据;您只是告诉它您希望它指向一个新的不可更改数据段。

    您真正遇到可变对象和不可变对象之间差异问题的唯一一次是您尝试直接修改 myString(例如,将“s are cool”附加到它或其他东西)。

    换句话说,任何一个类都允许您将任何字符串“更改”为任何其他字符串,但是您用来执行此操作的方法会非常不同。例如,要使用可变字符串将“cat”转换为“CAT”,您可以遍历每个字符并简单地将其设为大写(因为您可以修改可变字符串的内容)。另一方面,对于不可变字符串,您必须先将原始字符串复制到其他地方,对其进行修改,然后将变量重定向到这个新的 NSString。

    以下链接可能有用: http://www.kirupa.com/forum/showthread.php?t=307928 http://forums.macrumors.com/showthread.php?t=467099

    我还建议您进行一些谷歌搜索;这是一个涉及到总体发展的问题,是一个比较重要的概念。它也在互联网上的其他地方被讨论到死。

    【讨论】:

    • 在任何地方都使用 NSMutableString 会“更安全”和“更灵活”吗?他们说有“内存成本”和“速度成本”……但是……多少?我的数百万池中的 20 个额外字节?或者将我的应用程序减慢 0.01 秒? (“永远不必担心可变变量”的好处似乎值得。)还是这样?
    • 如果您正在使用并发编程(多线程等),很高兴知道字符串的内容在您使用它的过程中不会改变。如果你不得不担心这一点,你可能会在做任何其他事情之前制作一个字符串的副本,这样没有人会改变它。不变性使您不必复制字符串。这对于像 NSArray 和 NSDictionary 这样的大型结构来说变得更加重要。如果您只有一个线程(如果您不知道这意味着什么,那么您只有一个线程),那么在任何地方都使用可变对象可能会很好。
    • 即使您使用的线程不超过一个,也很高兴知道一个对象是否可以从您下方更改出来。一般来说,我发现大多数时候使用不可变数据结构更简单。如果我创建了一个 NSArray,将其提供给其他人,然后继续使用它,那么了解是否有人在我背后更改了它会很有帮助。简而言之,在任何地方使用 mutable 更容易编写,但更难调试。
    • 为什么我要在我的代码的其他部分在我不知情的情况下更改我的变量的情况下编写代码?这不就是普通的糟糕编程吗?
    【解决方案5】:

    一个不可变的字符串(或者实际上,任何不可变的对象)是一个在初始化后根本无法更改的字符串。

    这是在(伪)伪代码中使用不可变字符串的优势:

    // if using mutable strings
    let a = "Hello World";
    let b = a;
    a.replace("Hello", "Goodbye");
    

    现在持有什么? “你好世界”? “世界再见”? 现在 b 持有什么?

    如果字符串是可变的,那么它可能包含“再见世界”。这可能是你想要的。可能不是。

    通过不变性,很明显 b 仍然指向原始字符串,因为 replace 方法不能更改实际字符串,而是返回对新字符串的引用。

    您可能在此示例中看不到太多好处。但是如果 a 和 b 在代码的不同部分或不同线程中被引用和使用,则使用不可变引用会消除很多潜在的错误。

    【讨论】:

      【解决方案6】:

      默认情况下,目标 C 语言中使用的 NSString 是不可变的。 NSMutableString 用于声明和定义可变字符串。不可变字符串中的任何内容都无法更改。不是长度,不是字符,什么都没有。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多