Is there any reason not to return a mutable object where one is not expected? - objective-c

I have a number of functions similar to the following:
+ (NSArray *)arrayOfSomething
{
NSMutableArray *array = [NSMutableArray array];
// Add objects to the array
return [[array copy] autorelease];
}
My question is about the last line of this method: is it better to return the mutable object and avoid a copy operation, or to return an immutable copy? Are there any good reasons to avoid returning a mutable object where one is not expected?
(I know that it is legal to return a NSMutableArray since it is a subclass of NSArray. My question is whether or not this is a good idea.)

This is a complex topic. I think it's best to refer you to Apple's guidelines on object mutability.
Apple has this to say on the subject of using introspection to determine a returned object's mutability:
To determine whether it can change a received object, the receiver must rely on the formal type of the return value. If it receives, for instance, an array object typed as immutable, it should not attempt to mutate it. It is not an acceptable programming practice to determine if an object is mutable based on its class membership
(my emphasis)
The article goes on to give several very good reasons why you should not use introspection on a returned object to determine if you can mutate it e.g.
You read a property list from a file. When the Foundation framework processes the list it notices that various subsets of the property list are identical, so it creates a set of objects that it shares among all those subsets. Afterwards you look at the created property list objects and decide to mutate one subset. Suddenly, and without being aware of it, you’ve changed the tree in multiple places.
and
You ask NSView for its subviews (subviews method) and it returns an object that is declared to be an NSArray but which could be an NSMutableArray internally. Then you pass that array to some other code that, through introspection, determines it to be mutable and changes it. By changing this array, the code is mutating NSView’s internal data structures.
Given the above, it is perfectly acceptable for you to return the mutable array in your example (provided of course, you never mutate it yourself after having returned it, because then you would be breaking the contract).
Having said that, almost nobody has read that section of the Cocoa Objects Guide, so defensive programming would call for you to make an immutable copy and return that unless performance profiling shows that it is a problem to do that.

Short Answer: Don't do it
Long Answer: It depends. If the array is getting changed while being used by someone who expects it be static, you can cause some baffling errors that would be a pain to track down. It would be better to just do the copy/autorelease like you've done and only come back and revisit the return type of that method if it turns out that there is a significant performance hit.
In response to the comments, I think it's unlikely that returning a mutable array would cause any trouble, but, if it does cause trouble, it could be difficult to track down exactly what the issue is. If making a copy of the mutable array turns out to be a big performance hit, it will be very easy to determine what's causing the problem. You have a choice between two very unlikely issues, one that's easy to solve, one that's very difficult.

Related

Should I use == or [NSManagedObject isEqual:] to compare managed objects in the same context?

Let's say variable A and B hold instances of managed objects in the same managed object context. I need to make sure that they are associated with the same "record" in the persistent store. The section on Faulting and Uniquing in the Core Data Programming Guide says that:
Core Data ensures that—in a given managed object context—an entry in a persistent store is associated with only one managed object.
From this, it seems that a pointer comparison is sufficient for my purpose. Or does it ever make sense to use isEqual: to compare managed objects in the same context?
Use == to determine if two pointers point to the same object. Use -isEqual to determine if two objects are "equal", where the notion of equality depends on the objects being compared. -isEqual: normally compares the values returned by the -hash method. I wrote previously that it seemed possible that -isEqual: might return true if two managed objects contain the same values. That's clearly not right. There are some caveats in the docs about making sure that the hash value for a mutable object doesn't change while it's in a collection, and that knowing whether a given object is in a collection can be difficult. It seems certain that the hash for a managed object doesn't depend on the data that that object contains, and much more likely that it's connected to something immutable about the object; the object's -objectID value seems a likely candidate.
Given all that, I'm changing my opinion ;-). Each record is only represented once in a given context, so == is probably safe, but -isEqual: seems to better express your intention.
Pointer comparison is fine for objects retrieved from a single managed object context, the documentation on uniquing you quote promises as much.
ObjectID should be used for testing object equality across managed object contexts.
isEqual does not do attribute tests, because it is documented to not fault the object. In fact, looking at the disassembled function it is definitely just a pointer compare.
So the semantics of the equality test for managed objects are simply "points to the same object (record) in the managed object context" and will compare false for objects in different contexts.
Warning: Since NSManagedObject isEqual compares objectIDs, a comparison can fail if one instance is using the temporary objectID and the other instance is using the permanent objectID.
Background: When an NSManagedObject is created, it is assigned a temporary objectID. It is converted into a permanent objectID when the NSManagedObject is actually persisted into the store. You can see the difference if you print the objectID:
x-coredata:///MyEntity/t03BF9735-A005-4ED9-96BA-462BD65FA25F118 (temporary ID)
x-coredata://EB8922D9-DC06-4256-A21B-DFFD47D7E6DA/MyEntity/p3 (permanent ID)
When an objectID is converted to permanent, instances of the NSManagedObject in other threads and collections are not updated. So if you put an NSManagedObject into an NSArray when it has a temporary objectID, using methods like containsObject will fail if you try to find the object with the permanent objectID. Remember containsObject uses isEqual.
Finally, a couple of useful methods are NSManagedObjectID isTemporaryID and NSManagedObjectContext obtainPermanentIDsForObjects:error:.

NSArray property: copy or retain?

According to this: NSString property: copy or retain?
For NSString/NSMutableString, copy is recommended.
How about NSArray/NSMutableArray?
Since you're asking about NSArray (rather than NSMutableArray), you should use copy. NSArray is immutable, so you don't expect a property of that type to change. But NSMutableArray is a subclass of NSArray, so it's perfectly valid for someone to pass in a NSMutableArray. If you just retain that object, then it may change right under your nose. If you copy rather than retain, then the object won't change.
However, you should be aware that when you copy a container like NSArray, you're copying the container only and not its contents. If the array contains mutable objects, the contents of those objects may change even though the array itself is immutable.
choose copy, unless you have a very specific reason not to, as well as all the supporting code/interface to back that up.
i detailed the rationale and several implications here:
NSMutableString as retain/copy
that example is based on NSStrings, but the same applies for NSArrays.
If it is a problem when the underlying data changes, use copy. In fact, this is what you want most of the time, as changing data behind someone's back is a good source for bugs.
Note that copy will essentially just be a retain for an NSArray. Only when you throw an NSMutableArray in, there is more work involved.
From the link you included, it pretty much comes down to this: NSString property: copy or retain?
If you want to make sure the value of the object won't change during execution, you use the copy attribute, otherwise retain will be fine. Generally, retain will be ok for NSMutableArrays and NSArrays (as well as many other objects) as you are (usually) more interested in the object then in the value it contains. In case of an NSString you are always interested in the value, so you copy it to make sure it won't change.
#jlehr:
It depends if the developer is interested in the actual value or not. Whenever interested in the actual value, use copy (since you don't want the value to change during execution), otherwise retain is fine. From Apple's docs:
It is common practice in Objective-C code to copy value objects—objects that represent attributes. C-type variables can usually be substituted for value objects, but value objects have the advantage of encapsulating convenient utilities for common manipulations. For example, NSString objects are used instead of character pointers because they encapsulate encoding and storage.
Also from Apple's docs, on the topic of value objects:
A value object is in essence an object-oriented wrapper for a simple data element such as a string, number, or date. The common value classes in Cocoa are NSString, NSDate, and NSNumber. Value objects are often attributes of other custom objects you create.

Imutability in Objective-c

I'm beginning an objective-c project. I have a question regarding 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 a givenName and surname, but might also have a fullName that combines those two, and it might have a nameOrder that indicates which comes first. If you make Person mutable, then there can be points in time that fullName might be incorrect because you have changed the surname but not the givenName (perhaps one of them is still nil). 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 let Person be mutable, but create a separate immutable Name 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 immutable Address 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 because EmailAddress 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.

What happens when an NSArray element gets deallocated?

Let's suppose I create a few objects and I add them to an array.
House *myCrib = [House house];
House *johnHome = [House house];
House *lisaHome = [House house];
House *whiteHouse = [House house];
NSArray *houses = [NSArray arrayWithObjects: myCrib, johnHome, lisaHome, whiteHouse, nil];
Normally, all House objects have a retain count of two, but they're being autoreleased once. After a while, I decide to release myCrib, even if I'm not the owner — I never retained or initialized.
[myCrib release];
The retain count should drop to zero and my object should be deallocated. My question now is: will this illegal action cause my app to work erroneously or even crash, or will NSArray simply delete my object from its list with bad consequences.
I'm looking for a way to maintain a list of objects, but I want the list to maintain itself. When some object disappears, I want the reference to it to disappear from my array gracefully and automatically. I'm thinking of subclassing or wrapping NSArray.
Thank you.
My question now is: will this illegal
action cause my app to work
erroneously or even crash, or will
NSArray simply delete my object from
its list with bad consequences.
Your array now has an invalid object pointer. There's no way to tell that the pointer is invalid just by looking at it, and the array isn't notified that the object has been deallocated. The problem isn't with the array, after all, the problem is with the code that improperly releases the object. So yes, the application will likely crash or otherwise behave incorrectly due to that bad pointer, and no, NSArray won't detect and deal with the problem for you.
I'm looking for a way to maintain a
list of objects, but I want the list
to maintain itself. When some object
disappears, I want the reference to it
to disappear from my array gracefully
and automatically.
If the objects in the list are all instances of a common class, you could define your own memory management methods that both retain/release the object and add/remove it from the list, or broadcast appropriate notifications in case there can be multiple lists. I suppose you could even override -retain and -release for this purpose, but I'd think long and hard about that before doing it, and document it well if you do; it's not the sort of thing that other developers would expect.
Another option might be Core Data. If you delete a managed object from the object graph, it'll disappear from any relationships. Strictly speaking, a to-many relationship is a set, not a list, but the difference may not be a concern for your purposes.
Update: I just noticed that you didn't tag your question ios. If you're working under MacOS X, you should definitely take a look at NSPointerArray. If you use garbage collection, NSPointerArray can be configured to use weak references and to replace references to collected objects with null references. This is exactly what you seem to be looking for.
You should not release myCrib if you are not the owner. To do so is a violation of the memory management guidelines and will make your code extremely difficult to maintain. I cannot stress enough that you absolutely should never do this under any sort of circumstance. You're asking for crashes; the array has declared ownership of the object, and you must not subvert that ownership in any way.
So the answer here is: your code is absolutely wrong and you should fix it. If you can't fix it, you should trash it and start over and keep rewriting it until you've come up with another way to achieve the same effect without subverting object ownership. I guarantee that it's possible.
If what you want is a weak-referencing array, then there are a couple ways you can do this (this was just asked a couple of days ago):
NSPointerArray - weakly references its pointers. When you use garbage collection, they're autozeroing (ie, the pointers get removed when the object is deallocated). Unfortunately, this is not available on iOS.
CFMutableArrayRef - you can specify a custom retain and release callback, or just not specify one at all. If you leave them out, the array will simply not retain the objects it contains. However, this does not automatically remove the pointer when the object is deallocated.
DDAutozeroingArray - an NSMutableArray subclass I wrote the other day to provide a weakly-referencing and auto-zeroing array that works on both Mac OS and iOS. However, I strongly encourage you to use this only as a last resort; There are probably much better ways of doing what you're looking for. https://github.com/davedelong/Demos
I'm looking for a way to maintain a
list of objects, but I want the list
to maintain itself. When some object
disappears, I want the reference to it
to disappear from my array gracefully
and automatically. I'm thinking of
subclassing or wrapping NSArray.
If I have understood right, what you want is an array of weak references. Then, you might be interested in reading this post.
You're asking for a crash here. Your NSArray will still have a reference to the object that now no longer exists -- and who knows what it will be pointing to after a while?
Subclassing NSArray might not be the answer either. It's a class cluster which, in short, means that it's harder to subclass than you might hope.
Not entirely sure how you'd implement this. Something like the element sending a notification when they're about to be deallocated which the array would then pick up. You'd need to be careful that you didn't leak or over-release your objects.
I created a wrapper class — in my code it's called a controller — which maintains the (mutable) array for me. I initialize the controller class in my view controllers — the place where I need them — instead of using an array directly.
No invalid code for me. :-p

Using non-copyable object as key for NSMutableDictionary?

I tried to figure out this code referencing: Cocoa: Dictionary with enum keys?
+ (NSValue*)valueWithReference:(id)target
{
return [NSValue valueWithBytes:&target objCType:#encode(id*)];
}
And,
[table setObject:anObject forKey:[NSValue valueWithReference:keyObject]];
But it feels something not good. Any recommendations?
You're absolutely right it's not good.
For one, you're encoding the wrong type (it should be #encode(id), not #encode(id*)), but in most cases this shouldn't cause a big problem.
The bigger problem is that this completely ignores memory management. The object won't be retained or copied. If some other code releases it, it could just disappear, and then your dictionary key will be a boxed pointer to garbage or even a completely different object. This is basically the world's most advanced dangling pointer.
You have two good options:
You could either add NSCopying to the class or create a copyable subclass.
This option will only work for objects that can meaningfully be copied. This is most classes, but not necessarily all (e.g. it might be bad to have multiple objects representing the same input stream)
Implementing copying can be a pain even for classes where it makes sense — not difficult, per se, but kind of annoying
You could instead create the dictionary with the CFDictionary API. Since Core Foundation types don't have a generic copy function, CFDictionary just retains its keys by default (though you can customize its behavior however you like). But CFDictionary is also toll-free bridged with NSDictionary, which means that you can just cast a CFDictionaryRef to an NSDictionary* (or NSMutableDictionary*) and then treat it like any other NSDictionary.
This means that the object you're using as a key must not change (at least not in a way that affects its hash value) while it's in the dictionary — ensuring this doesn't happen is why NSDictionary normally wants to copy its keys
For the later reference.
Now I know that there are some more options.
Override methods in NSCopying protocol, and return the self instead of copying itself. (you should retain it if you are not using ARC) Also you ensure the object to always return same value for -hash method.
Make a copyable simple container class holds strong reference to the original key object. The container is copyable but, it just passes original key when it being copied. Override equality/hash methods also to match semantics. Even just an instance of NSArray contains only the key object works well.
Method #1 looks pretty safe but actually I'm not sure that's safe. Because I don't know internal behavior of NSDictionary. So I usually use #2 way which is completely safe in Cocoa convention.
Update
Now we Have NSHashTable and NSMapTable also in iOS since version 6.0.
I'm not 100% sure about the correctness of this solution, but I'm posting it just in case.
If you do not want to use a CFDictionary, maybe you could use this simple category:
#implementation NSMutableDictionary(NonCopyableKeys)
- (void)setObject:(id)anObject forNonCopyableKey:(id)aKey {
[self setObject:anObject forKey:[NSValue valueWithPointer:aKey]];
}
- (id)objectForNonCopyableKey:(id)aKey {
return [self objectForKey:[NSValue valueWithPointer:aKey]];
}
- (void)removeObjectForNonCopyableKey:(id)aKey {
[self removeObjectForKey:[NSValue valueWithPointer:aKey]];
}
#end
This is a generalization of a similar method I saw online (can't find the original source) for using an NSMutableDictionary that can store objects with UITouch keys.
The same restriction as in Chuck's answer applies: the object you're using as a key must not change in a way that affects its hash value and must not be freed while it's in the dictionary .
Also make sure you don't mix -(void)setObject:(id)anObject forNonCopyableKey:(id)aKey and - (id)objectForKey:(id)aKey methods, as it won't work (the latter will return nil).
This seems to work fine, but there might be some unwanted side effects that I am not thinking of. If anybody finds out that this solution has any additional problems or caveats, please comment.