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 (Cocoa-dev@lists.apple.com)

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:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to [EMAIL PROTECTED]

Reply via email to