Re: Problems with Key Observing Registration Performance
Re: Problems with Key Observing Registration Performance
- Subject: Re: Problems with Key Observing Registration Performance
- From: Ken Thomases <email@hidden>
- Date: Wed, 10 Sep 2008 04:06:08 -0500
On Sep 9, 2008, at 8:48 PM, Markus Spoettl wrote:
On Sep 9, 2008, at 5:28 PM, Markus Spoettl wrote:
These numbers come from a test case with 140 objects, when I double
the object number, the test never finishes (at least not within 10
minutes).
OK, I did some more testing and timing and there is a solution -
which I don't understand:
Testing with 326 objects, adding each of the objects to the array
like this
NSMutableArray *kvoArray = [self mutableArrayValueForKey:@"array"];
Have you implemented the KVC indexed accessors for the "array"
property? If not, then mutations of it will be quite inefficient.
Every mutation will in fact replace the array with the modified
array. See the note in the comments at the declaration of
mutableArrayValueForKey: in NSKeyValueCoding.h.
for (MyObject *obj in inputData) {
[kvoArray addObject:newObject];
If you have implemented the KVC indexed accessors, then you should
probably go ahead and use them directly, instead of the proxy returned
by mutableArrayValueForKey:. In general, if you're using KVC with a
key that's known at compile time, then you should just be using the
non-KVC means of accessing the same property.
Also, if you're really just adding all of the objects in one array to
another array, there are bulk insertion accessors that are more
efficient: -insert<Key>:atIndexes: or -
replace<Key>AtIndexes:with<Key>: (note that "Key" is typically a
plural noun for to-many properties; also, these KVC accessors are only
documented in the NSKeyValueCoding.h, unfortunately).
}
This takes 580 seconds. Each add causes a chain reaction of events
that eventually adds a new NSView to the collection view. I've
experimented with setting the whole array at once using -setArray:
but that does not make any difference.
However, adding an auto-release pool does make a huge difference:
NSMutableArray *kvoArray = [self mutableArrayValueForKey:@"array"];
for (MyObject *obj in inputData) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
[kvoArray addObject:newObject];
[pool release];
}
The same operation now takes 60 seconds. That's 10% of the original
time.
What I don't understand is why adding the auto-release pool has such
a dramatic impact on registering observers on the objects. Anyone
know why?
If something is observing the "array" property, then any modification
to that property has knock-on effects. Each change causes KVO change
notifications to be sent out. Each observer will do some work in
response to those notifications. That work may create a bunch of
autoreleased objects. If you don't drain the autorelease pool, then
those objects may accumulate and force the application to grow its
memory footprint, which can be expensive. That's another reason to
use bulk mutator methods, which can generate few bulk KVO
notifications instead of many one-off notifications.
One last suggestion: have you considered whether -[NSArray
addObserver:toObjectsAtIndexes:forKeyPath:options:context:] may be
applicable to your circumstances? It is documented as being
"potentially much faster than repeatedly invoking
addObserver:forKeyPath:options:context:".
Cheers,
Ken
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden