[This is a re-send as my previous message has been sitting in the moderators queue for ~week now...]
I've got an odd question. I haven't found anything via Google that matches it exactly, but it could be that I'm just searching for the wrong thing. I have a need to create subclasses of NSArray and NSDictionary. The @interface line is "@interface MYArray : NSArray" (etc). No problems here- implemented the various required class cluster interfaces. (In the examples below, I only discuss the "array" collection class, but assume that the same "thing" applies to the dictionary collection class, modulo the obvious differences) I also have a need to create mutable versions of my custom subclasses.... (if you're curious as to why I'm doing all this, the short answer is "performance"... and yes, /all/ of it is justified by extensive (hours and hours) of profiling / Shark.app... which are in no way "micro-benchmarking" results. It's for serializing/deserializing JSON- https://github.com/johnezang/JSONKit - I can serialize and deserialize JSON faster than binary plists can for the exact same data... I beat binary plist serialization by such a huge margin I can literally gzip the result and STILL beat binary .plists!). In all cases, the classes are guaranteed to only be created by my code and it is documented that it is verboten to directly instantiate objects of these special classes. It is also documented that it is verboten to do any kind of subclassing of these classes. They are purely "private implementation details". They DO need to behave and respond "identically" to an instantiated instance of their respective class (that is to say the class and instance methods used to instantiate objects of these special classes are documented to be verboten / undefined behavior). Unless there is an exceptionally good reason, they should be completely compatible in every way and indistinguishable from their NSArray / NSMutableArray Cocoa concrete instances. There is no .h header file publicly exposed for these special classes- they don't add any extra behavior. In effect, they are the epitome of "duck typed" collection objects- the exposed public interfaces that eventually return these custom classes are prototyped with -(NSArray *). I am currently using "@interface MYMutableArray : NSMutableArray". But just like NSMutableArray is a subclass of NSArray, MYMutableArray is a subclass of MYArray, not really NSMutableArray. The "problem" is that with the @interface written as MYMutableArray : NSMutableArray", I don't inherit the MYArray methods, which I'd very much like to. While one possible solution is to just copy and paste the code from MYArray in to the MYMutableArray and chalk it up to "required bloat", I would much rather only have a single copy of the reusable immutable code- one advantage is that changes, if required, only need to be made in one place, instead of remembering to keep both copies in sync. To accomplish this, I've used a form of "method swizzling", but it's not quite method swizzling as the term is normally used. It's more like "method copying". Here's the current code: static void _swizzleInstanceMethod(Class fromClass, Class toClass, SEL selector) { fromClass = class_isMetaClass(fromClass) ? objc_getClass(class_getName(fromClass)) : fromClass; toClass = class_isMetaClass(toClass) ? objc_getClass(class_getName(toClass)) : toClass; class_replaceMethod(fromClass, selector, method_getImplementation(class_getInstanceMethod(toClass, selector)), method_getTypeEncoding(class_getInstanceMethod(fromClass, selector))); } static void _swizzleClassMethod(Class fromClass, Class toClass, SEL selector) { fromClass = class_isMetaClass(fromClass) ? fromClass : objc_getMetaClass(class_getName(fromClass)); toClass = class_isMetaClass(toClass) ? toClass : objc_getMetaClass(class_getName(toClass)); class_replaceMethod(fromClass, selector, method_getImplementation(class_getClassMethod(toClass, selector)), method_getTypeEncoding(class_getClassMethod(fromClass, selector))); } I'm not 100% certain that the from / to MetaClass bits are needed as they are probably redundant / unnecessary with the later class_getClassMethod / class_getInstanceMethod calls (i.e., they probably automatically do the exact same meta class checks). I am using class_replaceMethod, which for now isn't a problem since I'm assuming a "modern" 10.5+ runtime. I can't find a handy reference for the minimum version of iOS that this function is supported (I'm sort of assuming "all" as it started as a "modern" objc abi). If, for some reason, < 10.5 / "modern" ObjC run time support is required, I suppose I could hack up class_replaceMethod equivalent behavior, but this isn't a pressing issue right now. These functions are used in the mutable classes +load method to: { Class MYMutableArrayClass = objc_getClass("MYMutableArray"); Class MYArrayClass = objc_getClass("MYArray"); // We swizzle the methods from MYArray in to this class (MYMutableArray). _swizzleClassMethod(MYMutableArrayClass, MYArrayClass, @selector(allocWithZone:)); _swizzleInstanceMethod(MYMutableArrayClass, MYArrayClass, @selector(dealloc)); _swizzleInstanceMethod(MYMutableArrayClass, MYArrayClass, @selector(count)); _swizzleInstanceMethod(MYMutableArrayClass, MYArrayClass, @selector(objectAtIndex:)); _swizzleInstanceMethod(MYMutableArrayClass, MYArrayClass, @selector(getObjects:range:)); _swizzleInstanceMethod(MYMutableArrayClass, MYArrayClass, @selector(countByEnumeratingWithState:objects:count:)); } ... which are all the methods I have specifically created in the immutable class that I want to "inherit" in MYMutableArray. So it's not automagic, I have to manually keep this list in sync with the immutable methods I've written. For my purposes, this is OK, although I suppose a super whiz bang version could walk all the methods for the MYArray and NSArray classes, and look for differences when the MYArray method != NSArray method, but I don't need that much coolness. The collection objects themselves contain either your standard Cocoa NSString / NSNumber / etc (what you would expect for JSON, basically) or other MY... collection class objects. I'm curious if anyone sees any problems with this approach... Again, I haven't found anything on the web that covers this exactly, so there's no prior experience to draw on / best practices. This is the first time I've had to do both mutable and immutable classes of a collection class cluster. I didn't even anticipate that there was a problem until I literally wrote "@interface MYMutableArray : NSMutableArray .... ergh, but how exactly do I inherit the MYArray methods I already wrote... ? hmmmm" Anyone from Apple want to comment on how kosher this is likely to be for an iOS / iPhone / iPad app? I ask because the three20 framework started to cause rejections due to its use of method swizzling. However, in the three20 case, they were clearly doing something that was borderline questionable (I think they swizzled -dealloc of -UIView or something to their own -dealloc replacement to hack in behavior?). I'm not doing anything like that, it's a fairly legitimate (at least, IMHO) use of swizzling, and I'm only swizzling over the immutable methods that I've written code for- I'm not overriding / swizzling the NSArray / NSMutableArray methods at all- the swizzling only happens to my (mutable) classes methods. I've considered the "assume everyone and everything practices proper duck typing" and just make @interface MYMutableArray : MYArray. There is one corner case that I can think of where this breaks: [myMutableArrayInstance isKindOfClass:[NSMutableArray class]]. Granted, doing this is frowned on as "not proper Objective-C programming", but none the less, I'm sure some people do it. I'm also not entirely sure how this might interact with serialization, either NSCoder or property lists. Currently, my spot checks of NSCoder behavior causes the instances to be serialized as NSArray or NSMutableArray, which is just fine and what I want since the sole reason that I'm creating these custom classes is for bulk creation of collection objects very, very quickly. Can anyone think of corner cases in which these would not behave "identically" to their respective concrete Cocoa versions? KVO / KVC? Anything "weird" but still considered legitimate? The CoreFoundation CFArray... / CFDictionary calls seem to work as expected (but I can't say I've done a comprehensive test of everything). Fast enumeration and block based enumeration works, though come to think of it I haven't tried the "parallel" option. Distributed Objects... CoreData? I'd like to provide "maximally compatible" if at all possible, and if not, then clearly document the limitations / caveats. TIA. _______________________________________________ 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 arch...@mail-archive.com