Objective-c中的不可替换性

Objective-c中的不可替换性,objective-c,Objective C,我正在开始一个objective-c项目。我有一个关于不变性的问题。只要有可能,让对象不可变值得吗?如果我更新一个字段,我必须返回一个指向新对象的指针,并取消锁定旧对象。如果我经常这样做,可能会出现性能问题。此外,代码可能会更加冗长。毫无疑问,还有其他考虑。你觉得怎么样 编辑:让我澄清一下我写“更新字段”的意思。通常,当您更新一个字段时,您调用setter并只更改该字段的值。如果对象是不可变的,setter实际上不会更新字段,而是创建一个新实例,所有字段都具有相同的值,但要更新的字段除外。在ja

我正在开始一个objective-c项目。我有一个关于不变性的问题。只要有可能,让对象不可变值得吗?如果我更新一个字段,我必须返回一个指向新对象的指针,并取消锁定旧对象。如果我经常这样做,可能会出现性能问题。此外,代码可能会更加冗长。毫无疑问,还有其他考虑。你觉得怎么样

编辑:让我澄清一下我写“更新字段”的意思。通常,当您更新一个字段时,您调用setter并只更改该字段的值。如果对象是不可变的,setter实际上不会更新字段,而是创建一个新实例,所有字段都具有相同的值,但要更新的字段除外。在java中:

class User{
   private String firstName;
   private String lastName;
   public User(String fn, String ln){ firstName = fn; lastName = ln; }

   public User setFirstName(String fn){ return new User(fn, lastName); }

}

由于可变对象的性能开销,请尽可能使用不可变对象

编辑:通常上述情况应该是正确的,但在某些情况下,NSMutableArray的性能实际上比NSArray更好。请在网站上阅读更多信息:

在上阅读更多关于可变性的内容(对于Mac/iOS开发人员来说,这是一个很棒的博客,所以请将其放在您的收藏夹中!)

我还想补充一点,很多对象都有-mutableCopy实例方法,这是一种易于使用的方法,用于从不可变对象(如NSArray或NSString)检索可变副本,例如:

NSArray *array = [NSArray arrayWithObjects:@"apple", @"pear", @"lemon"];
NSMutableArray *mutableArray = [array mutableCopy];
// remember to release the mutableArray at some point 
//    because we've created a copy ...

请记住,在某些情况下,可变对象更容易使用,例如,对于UITableView,它使用的数据源会随着时间的推移发生很多变化。

与任何其他命令式语言一样:这取决于。当我们使用不可变对象时,我已经看到了代码性能的提升,但它们通常也是不经常修改的对象,它们从存档中读取或由用户设置,然后传递给所有不同的代码位。对于所有的代码来说,这样做似乎不值得,至少对我来说不值得,除非您计划大量利用多处理并理解您正在进行的权衡。

可变或不可变对象是否最佳取决于具体情况,因此最好给出一个更具体的示例进行讨论。但这里有一些事情需要考虑

  • 通常,对象属性在某种程度上是相互关联的。例如,一个
    可能有一个
    givenName
    ,但也可能有一个
    全名
    ,它可以有一个
    nameOrder
    指示哪一个先到。如果您使Person可变,那么可能在某个时间点,
    全名
    可能不正确,因为您更改了
    姓氏
    ,但没有更改
    givenName
    (可能其中一个仍然是
    nil
    )。您现在需要一个更复杂的接口来保护您不受此影响

  • 如果其他对象使用这个可变的
    ,它们必须使用KVO或通知来发现它何时发生了更改。相互关联的字段可能会独立地更改,这一事实会使这一点变得复杂,您会发现自己正在编写代码来合并这些更改

  • 如果某些属性组合是非法的,那么可变对象可能很难进行错误检查。不可变对象在构造时可以执行其所有检查

  • 在可变和不变之间有一些中间地带。在上面的
    Person
    和各种名称属性的示例中,简化大部分属性的一种方法是让
    Person
    可变,但创建一个单独的不可变
    name
    对象,该对象包含各个部分。通过这种方式,您可以确保整个名称以原子方式进行了变异

  • 不可变对象大大简化了多线程代码。可变对象需要更多的锁定和同步,这会严重影响性能和稳定性。这段代码很容易出错。相比之下,不可变对象是微不足道的

  • 关于创建和丢弃对象,不可变对象还提供了共享的机会,如果可能有许多对象指向相同的数据内容,这可以使它们非常有效。例如,在我们的
    Person
    示例中,如果我创建一个不可变的
    Address
    对象,那么住在同一地址的每个人都可以共享同一个对象。如果一个人改变了地址,这不会影响其他人

  • 作为上面的一个例子,我的代码中有很多电子邮件地址。同一个字符串反复出现是非常常见的。使
    EmailAddress
    不可变,并且只允许使用
    +emailAddressForString:
    构造它,允许类维护缓存,这可以节省大量内存和时间来构造和销毁字符串对象。但这只是因为
    电子邮件地址
    是不可变的


无论如何,我的经验是,为了简单起见,最好是错误地使用不可变的数据对象,并且只有在不可变性造成性能问题时才使数据对象可变。(当然,这只适用于数据对象。有状态对象是另一回事,当然它们的性质需要是可变的,但这并不意味着它们的每个部分都必须是可变的。)

我认为更大的不可变性问题是,如果你做了很好的设计,使数据在这种情况下保持不可变,当它是可变的,那么它将更容易利用像大中央调度和其他并行化这样的东西,你可以实现更大的潜在收益


作为旁注,从Java转到Objective C,我能给你的第一个技巧是抛弃公共和私有的概念。

根据定义,你不能更新不可变对象的“字段”,所以你的要求并不明确。此外,易变性问题并非特定于