Re: faster deep copies?
I wrote a -deepCopy method as part of a protocol on the common collection classes. It does a respondsToSelector: and calls -copy if it doesn't. So as long as my collection views cover all collection classes to create a new NSArray etc. containing copies of the same objects, it mostly works. Downsides: This will make immutable copies of mutable objects (if you called -mutableCopy where available, you might do the reverse), and you need to be careful that you don't miss adding -deepCopy to a class. Cheers, -- Uli Kusterer The Witnesses of TeachText are everywhere... http://www.zathras.de On Feb 14, 2013, at 3:07 AM, James Maxwell jbmaxw...@rubato-music.com wrote: I've run into a situation where I really need a deep copy of an object. I've implemented this using Apple's recommended approach with NSKeyedArchiver/Unarchiver, and it's nice, simple, and functional. But it's also pretty darn slow -- as in a clear, subjectively apparent performance hit. Has anybody had to find a way around this, and if so, what did you do? Or if anybody just has a nice, creative thought about another way of doing it, I'd love to hear about it. The object(s) being copied are custom classes, and there's a chance I may be able to get away with copying only certain properties (i.e., rather than archiving the entire graph from the root object), so I'll look into making a deepCopy method that's more selective. But I'd appreciate any thoughts in the meantime. Thanks in advance. J. ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/witness.of.teachtext%40gmx.net This email sent to witness.of.teacht...@gmx.net ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: faster deep copies?
What NSKeyedArchiver probably does is have a dictionary that maps the original object pointer values to the copied objects. So instead of just straight-out copying an object, it does: NSString* theKey = [NSString stringWithFormat: @%p, theOriginal]; id theCopy = [objectCopies objectForKey: theKey]; if( !theCopy ) { theCopy = [theOriginal copy]; [objectCopies setObject: theCopy forKey: theKey]; } That way, every object only gets copied once, and the copy re-used in other spots. That may be part of why it is slower. (NB - you could probably use an NSValue +valueWithUnretainedPointer: or whatever as the key, I just quickly typed this untested code into the e-mail) Cheers, -- Uli Kusterer The Witnesses of TeachText are everywhere... http://www.zathras.de On Feb 14, 2013, at 3:57 AM, Ken Thomases k...@codeweavers.com wrote: Your question prompted me to try to design an analog of NSKeyedArchiver, NSCode, and NSCoding that would generate the new object graph on the fly as it went instead of producing a data object. The idea is that the copier (the analog of the archiver/coder) would know which objects had already been copied and so would avoid over-duplicating them in the new graph. However, that ends up being hard because each object has to copy its related object before it's complete enough to be registered with the copier. So, it isn't successful in avoiding the potential for infinite recursion. ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: faster deep copies?
On 14 Feb 2013, at 02:07, James Maxwell jbmaxw...@rubato-music.com wrote: I've run into a situation where I really need a deep copy of an object. I've implemented this using Apple's recommended approach with NSKeyedArchiver/Unarchiver, and it's nice, simple, and functional. But it's also pretty darn slow -- as in a clear, subjectively apparent performance hit. Has anybody had to find a way around this, and if so, what did you do? Or if anybody just has a nice, creative thought about another way of doing it, I'd love to hear about it. The object(s) being copied are custom classes, and there's a chance I may be able to get away with copying only certain properties (i.e., rather than archiving the entire graph from the root object), so I'll look into making a deepCopy method that's more selective. But I'd appreciate any thoughts in the meantime. One possible approach to this (though not one that's going to be as fast as a custom deepCopy method), would be to implement your own NSCoder subclass. I have in the past made keyed archivers which are substantially quicker than apple's, and encode into substantially smaller byte formats. Thanks Tom Davie ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: faster deep copies?
On Feb 14, 2013, at 8:30 AM, Uli Kusterer wrote: On Feb 14, 2013, at 3:57 AM, Ken Thomases k...@codeweavers.com wrote: Your question prompted me to try to design an analog of NSKeyedArchiver, NSCode, and NSCoding that would generate the new object graph on the fly as it went instead of producing a data object. The idea is that the copier (the analog of the archiver/coder) would know which objects had already been copied and so would avoid over-duplicating them in the new graph. However, that ends up being hard because each object has to copy its related object before it's complete enough to be registered with the copier. So, it isn't successful in avoiding the potential for infinite recursion. What NSKeyedArchiver probably does is have a dictionary that maps the original object pointer values to the copied objects. So instead of just straight-out copying an object, it does: NSString* theKey = [NSString stringWithFormat: @%p, theOriginal]; id theCopy = [objectCopies objectForKey: theKey]; if( !theCopy ) { theCopy = [theOriginal copy]; [objectCopies setObject: theCopy forKey: theKey]; } That way, every object only gets copied once, and the copy re-used in other spots. That may be part of why it is slower. (NB - you could probably use an NSValue +valueWithUnretainedPointer: or whatever as the key, I just quickly typed this untested code into the e-mail) That's what I considered but it doesn't work. You can't add the copy into the archiver's database of already-copied objects until it's complete. But, for the case where the graph has cycles, making the complete copy will try to make copies of all its related objects first. When the cycle loops back to the same original, that original still does not have a copy in the database, so it tries to make another copy. Infinite recursion. Regards, 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: faster deep copies?
I've taken the plunge and written a mutable deep copy method for NSObject in my applications. So far, I've used it only to add interesting arbitrary objects to NSError userInfo dictionaries. Unliike Ken and Uli, I'd never thought about the circular references in object trees, but I ran into a different problem, which you should also watch out for, which is that descendant objects are not necessarily serializable, encodeable, or respond to -mutableCopy. https://github.com/jerrykrinock/CategoriesObjC/blob/master/NSObject%2BDeepCopy.h My next commit of that will have at least some warnings about circular references in object trees :) ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: faster deep copies?
On 14/02/2013, at 1:07 PM, James Maxwell jbmaxw...@rubato-music.com wrote: I've run into a situation where I really need a deep copy of an object. My question would be: are you really sure? Yes, there are times you need a deep copy, but surprisingly few. Often you can redesign your code not to need one --Graham ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: faster deep copies?
On 15 Feb 2013, at 01:25, Ken Thomases k...@codeweavers.com wrote: On Feb 14, 2013, at 8:30 AM, Uli Kusterer wrote: On Feb 14, 2013, at 3:57 AM, Ken Thomases k...@codeweavers.com wrote: Your question prompted me to try to design an analog of NSKeyedArchiver, NSCode, and NSCoding that would generate the new object graph on the fly as it went instead of producing a data object. The idea is that the copier (the analog of the archiver/coder) would know which objects had already been copied and so would avoid over-duplicating them in the new graph. However, that ends up being hard because each object has to copy its related object before it's complete enough to be registered with the copier. So, it isn't successful in avoiding the potential for infinite recursion. What NSKeyedArchiver probably does is have a dictionary that maps the original object pointer values to the copied objects. So instead of just straight-out copying an object, it does: NSString* theKey = [NSString stringWithFormat: @%p, theOriginal]; id theCopy = [objectCopies objectForKey: theKey]; if( !theCopy ) { theCopy = [theOriginal copy]; [objectCopies setObject: theCopy forKey: theKey]; } That way, every object only gets copied once, and the copy re-used in other spots. That may be part of why it is slower. (NB - you could probably use an NSValue +valueWithUnretainedPointer: or whatever as the key, I just quickly typed this untested code into the e-mail) That's what I considered but it doesn't work. You can't add the copy into the archiver's database of already-copied objects until it's complete. But, for the case where the graph has cycles, making the complete copy will try to make copies of all its related objects first. When the cycle loops back to the same original, that original still does not have a copy in the database, so it tries to make another copy. Infinite recursion. Why not keep a mutable dictionary M and on encountering an object (in the scanning phase) do: if object not in mutable dictionary M then add to M: key = address of object, value = NSNull continue walking the object tree else do nothing endif And in the second (copy) phase do: if value of object = NSNull then copy it and set the value in M to the copied object else just store a link to the already copied object. Should work with cycles. Might not be faster than NSArchive. Kind regards, Gerriet. ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: faster deep copies?
Well, yes, that's a good question. But I spent a good deal of time trying to find a way around it and couldn't. However, in the meantime I discovered that by using a home-spun -deepCopy method on just a couple of classes I was able to solve my mutation problem, without resorting to the wholesale NSKeyedArchiver approach of grabbing the entire object graph. So, problem solved. If I ever feel inclined to discover a deeper fix I will, but it won't be any time soon! J. On 2013-02-14, at 4:01 PM, Graham Cox graham@bigpond.com wrote: On 14/02/2013, at 1:07 PM, James Maxwell jbmaxw...@rubato-music.com wrote: I've run into a situation where I really need a deep copy of an object. My question would be: are you really sure? Yes, there are times you need a deep copy, but surprisingly few. Often you can redesign your code not to need one --Graham ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
faster deep copies?
I've run into a situation where I really need a deep copy of an object. I've implemented this using Apple's recommended approach with NSKeyedArchiver/Unarchiver, and it's nice, simple, and functional. But it's also pretty darn slow -- as in a clear, subjectively apparent performance hit. Has anybody had to find a way around this, and if so, what did you do? Or if anybody just has a nice, creative thought about another way of doing it, I'd love to hear about it. The object(s) being copied are custom classes, and there's a chance I may be able to get away with copying only certain properties (i.e., rather than archiving the entire graph from the root object), so I'll look into making a deepCopy method that's more selective. But I'd appreciate any thoughts in the meantime. Thanks in advance. J. ___ 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com
Re: faster deep copies?
On Feb 13, 2013, at 8:07 PM, James Maxwell wrote: I've run into a situation where I really need a deep copy of an object. I've implemented this using Apple's recommended approach with NSKeyedArchiver/Unarchiver, and it's nice, simple, and functional. But it's also pretty darn slow -- as in a clear, subjectively apparent performance hit. Has anybody had to find a way around this, and if so, what did you do? Or if anybody just has a nice, creative thought about another way of doing it, I'd love to hear about it. The object(s) being copied are custom classes, and there's a chance I may be able to get away with copying only certain properties (i.e., rather than archiving the entire graph from the root object), so I'll look into making a deepCopy method that's more selective. But I'd appreciate any thoughts in the meantime. I'd expect a -deepCopy method to be substantially faster even if it weren't any more selective about which properties get copied. The main difficulty is when your object graph may have cycles or diamonds. Archiving will store each object exactly once and all references to it will refer to that; then, on unarchiving, the references will be restored properly. A naive deep copy will cause an object which is referenced from two points in the object graph to end up as two separate objects in the new graph. And cycles can cause infinite recursion. Your question prompted me to try to design an analog of NSKeyedArchiver, NSCode, and NSCoding that would generate the new object graph on the fly as it went instead of producing a data object. The idea is that the copier (the analog of the archiver/coder) would know which objects had already been copied and so would avoid over-duplicating them in the new graph. However, that ends up being hard because each object has to copy its related object before it's complete enough to be registered with the copier. So, it isn't successful in avoiding the potential for infinite recursion. An obvious question is: have you analyzed the NSKeyedArchiver approach to understand why it's slow? Regards, 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: https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com This email sent to arch...@mail-archive.com