Imutability in Objective-c
I'm beginning an objective-c project. I have a question re开发者_StackOverflowgarding immutability. Is it worth trying to make objects immutable whenever I can? If I update a field, I have to return a pointer to a new object and dealloc the old. If I do this often, there might be performance issues. Also, the code will probably be more verbose. There are undoubtedly other considerations. What do you think?
Edit: Let me clarify what I mean when I write "update a field". Normally, when you update a field you call a setter and just change the value of the field. If the object is immutable, the setter does not actually update the field, instead it creates a new instance, with all the fields having the same value, except for the field you are trying to update. In 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); }
}
Use immutable objects whenever possible, due to the performance overhead of mutable objects.
Edit: Well, usually the above should be true, but it seems there are situations where NSMutableArray performance is actually better then NSArray. Read some more about it on the Cocos2d site:
Read some more about mutability on CocoaWithLove (great weblog for Mac / iOS developers so put it in your favorites!).
I'd also like to add that a lot of objects have the -mutableCopy instance method, this is an easy to use method to retrieve a mutable copy from an immutable objects, like a NSArray or NSString, e.g.:
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 ...
Just remember in some situations a mutable object is easier to use, for example for a UITableView that makes use of a datasource that is subject to a lot of changes over time.
Whether mutable or immutable objects are best is very situation dependent, so it's best if you give a more concrete example to discuss. But here are some things to think about.
Often object properties are somehow inter-related. For instance, a
Person
might have agivenName
andsurname
, but might also have afullName
that combines those two, and it might have anameOrder
that indicates which comes first. If you make Person mutable, then there can be points in time thatfullName
might be incorrect because you have changed thesurname
but not thegivenName
(perhaps one of them is stillnil
). You now need a more complex interface to protect you against this.If other objects use this mutable
Person
, they have to employ KVO or notifications to find out when it has changed. The fact that interrelated fields might change independently can make this complex, and you find yourself writing code to coalesce the changes.If some combinations of properties are illegal, mutable objects can be very hard to error check. An immutable object can do all of its checking when it is constructed.
There are some middle-grounds between mutable and immutable. In the above example of
Person
and various name properties, one way to simplify much of it is to letPerson
be mutable, but create a separate immutableName
object that contains the various parts. That way you can make sure that the entire name is mutated in an atomic way.Immutable objects greatly simplify multi-threaded code. Mutable objects require a lot more locking and synchronization, and this can significantly hurt performance and stability. It's very easy to screw this code up. Immutable objects in comparison are trivial.
To your point about creating and throwing away objects, immutable objects also give the opportunity for sharing, which can make them very efficient if there are likely to be many objects pointing to the same data contents. For instance, in our
Person
example, if I make an immutableAddress
object, then every person who lives at the same address can share the same object. If one changes their address, this doesn't impact all the others.As an example of the above, my code has a lot of email addresses in it. It's extremely common for the same string to show up over and over again. Making
EmailAddress
immutable, and only allowing it to be constructed with+emailAddressForString:
allows the class to maintain a cache and this can save significant memory and time to construct and destroy string objects. But this only works becauseEmailAddress
is immutable.
Anyway, my experience is that it's often better to err towards immutable data objects for simplicity, and only make the mutable when immutability creates a performance problem. (Of course this only applies to data objects. Stateful objects are a different thing, and of course need to be mutable by their nature, but that doesn't mean that every part of them must be mutable.)
As in any other imperative language: it depends. I've seen decent boosts in code performance when we use immutable objects, but they're also usually infrequently-modified objects, ones which are read out of an archive or set by a user and then passed around to all different bits of code. It doesn't seem worth doing this for all your code, at least not to me, unless you plan on heavily leveraging multiprocessing and understand the tradeoffs you're making.
I think the bigger immutability concern is that if you've done good design to keep your data marked immutable when it is such, and mutable when it is such, then it's going to be a lot easier to take advantage of things like Grand Central Dispatch and other parallelization where you could realize far greater potential gains.
As a side note, moving to Objective C from Java, the first tip I can give you is to ditch the notion of public and private.
精彩评论