# 18、尽量使用不可变对象

如8条，若把可变对象放到collection之后又修改其内容，那么很容易就会破坏set的内部数据结构，使其失去固有的语义。因此，建议大家尽量减少对象中的可变内容。

​ 尽量把对外公布出来的属性设为只读，而且只在确有必要时才将属性对外公布。

如：person有一个friends全部朋友的属性，放在一个“列表”（list）里外界可以增删。通常应该提供一个readonly属性返回不可变set(内部可变set的copy)供外界使用。

```objectivec
// .h
@property (nonatomic, strong, readonly) NSSet *friends;
- (void)addFriend:(Person *)person;
- (void)removeFriend:(Person *)person;

// .m
@property (nonatomic, strong, readwrite) NSSet *friends;
NSMutableSet *_interalFriends;
- (NSSet)firends {
  return [_interalFriends copy]; // 拷贝不可变版本
}
- (void)addFriend:(Person *)person {
  [_interalFriends addObject:person];
}
- (void)removeFriend:(Person *)person {
    [_interalFriends removeObject:person];
}
```

​ 如果直接提供可变版本`NSMutableSet`供外部使用，不是借助`addFriend:`与`removeFriend:`方法，而是直接操作此属性。这种过`分解耦数据`的做法很容易出bug。如：在添加或删除朋友时，`Person`对象可能还要执行其他操作，此时就等于直接从底层修改了其内部用于存放朋友对象的`set`。在`Person`对象不知情时，直接从底层修改`set`可能会令对象内的各个数据之间互不一致。

要点：

* 尽量创建不可变的对象
* 若某属性仅可于对象内部修改，则在`class-continuation分类`中将其由`readonly`属性扩展为`readwrite`属性
* 不要把可变的`collection`作为属性公开，而应提供相关方法修改对象中的可变`collection`
