Re: WTF? How can this work?
Re: WTF? How can this work?
- Subject: Re: WTF? How can this work?
- From: Chris Kane <email@hidden>
- Date: Sun, 19 Aug 2001 18:34:02 -0700
On Sunday, August 19, 2001, at 04:51 PM, Rainer Brockerhoff wrote:
In 10.1, the memory "loss" and immutability [of NS collections] are
recovered.
Chris, could you expand that last sentence a little more? How are they
"recovered"?
Instead of Foundation creating a CFMutableArray for all NSArrays, a
CFArray is created for allocated NSArrays and a CFMutableArray is
created for NSMutableArrays. Since the implementation for CF came right
from NS (and has additionally been improved upon as recently discussed,
as most mutable arrays are now managed as deques), the memory usage is
now within a small constant amount plus or minus what the "old NS"
implementation used.
Thus, if you do this:
id a = [[NSArray alloc] initWithObjects: myObj1, myObj2, nil];
[a addObject: anotherObj];
You'll get an exception, just like in the olden days. And the array has
just two slots of storage, for the two objects. Mutable collections
tend to have "extra slots" allocated to avoid reallocation on every
addition, which kills performance.
In the case of dictionaries and sets, the same thing was done for the
immutability/mutability. Storage use is actually less by a factor in
Mac OS X than in OPENSTEP, as I mentioned in a previous email.
I'm relieved to read your reply on the mutable question. Had you said
the implementations were different, I'd be asking you now - rather
plaintively - about the "secret method" Cocoa uses internally to
construct immutable non-empty NSArrays.
I don't understand. There's no secret -- use -[NSArray
initWithObjects:count:] or one of the other methods to get an immutable
non-empty NSArray. We use methods like -initWithObjects:count: too
internally. No magic.
As it is, it seems I'm doing the right thing in my own classes.
Whenever I need to return an NSArray from my method, I declare an
NSMutableArray internally, fill it with the information, then pass it
to the caller saying it's an NSArray. He's obliged to treat it as such.
Yes, that's the contract you're setting up. You don't really need an
immutable array unless (1) the extra memory used by mutable arrays is
significant because you have LOTS of these situations or (2) you have
clients of your API that aren't well-behave and you feel forcing them to
be well-behaved is more important than the cost of creating an immutable
copy.
As a side-note, this is one of the reasons we should always declare
object types instead of "id"s wherever possible - so the compiler can
complain that addObject: shouldn't be used here, and so forth.
This doesn't really make a difference. The return type only helps if
you're nesting like:
[[[NSArray alloc] initWith...] addObject: myObj];
but now you don't have a reference to the new array! In the usual
pattern:
NSArray *newArray = [[NSArray alloc] initWith...];
[newArray addObject: myObj];
it's the declaration of newArray that makes all the difference. Declare
it id instead, and no warning.
Chris Kane
Cocoa Frameworks, Apple