简体   繁体   中英

How can I clone a NSCoding compliant object into a subclass of it?

I have a custom subclass of NSPopUpButtonCell so that I can overwrite its drawBezelWithFrame:inView: method.

Currently, I have to create a fresh instance using initTextCell:pullsDown: and then copy all its properties by hand. That's rather tedious and error-prone as I may be missing some properties.

I wonder if I can use initWithCoder: for this task instead. I imagine I should be able to file the data from the existing NSPopUpButtonCell instance into an NSCoder object, eg into NSKeyedArchiver , and then file that data back into my NSPopUpButtonCell subclass. But I can't figure out how to accomplish that.

If all your subclass does is override methods, ie it does not add additional fields, then you can swizzle the class of your original NSPopupButtonCell , or a copy of it, so it becomes and instance of your subclass.

Apple implements KVO using this technique, in that case using a dynamically generated subclass. If your case the subclass is static, making it a lot easier, the outline of the code is:

object_setClass(<an NSPopupButtonCell instance>,
                [<your subclass> class]);

If you can safely change the class on the original instance then this involves no object creation or copying at all.

Remember you can only do this if the subclass changes behaviour only .

For another explanation see this answer .

HTH

Looks like I just used the wrong functions before. The solition is pretty straight-forward.

This code duplicates the properties of a NSPopUpButtonCell into a subclass of it, so that I can overwrite its draw... methods:

@interface MyPopup : NSPopUpButton
@end

@implementation MyPopup
- (instancetype)initWithCoder:(NSCoder *)coder {
    self = [super initWithCoder:coder];
    if (self) {
        // Set up the archiver
        NSMutableData *data = [NSMutableData data];
        NSKeyedArchiver *arch = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
        // Archive the cell's properties
        [self.cell encodeWithCoder:arch];
        [arch finishEncoding];
        // Set up the unarchiver
        NSKeyedUnarchiver *ua = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
        // Create a subclass of the cell's class, using the same properties
        MyCell *newCell = [[MyCell alloc] initWithCoder:ua];
        // Assign the new subclass object as the NSButton's cell.
        self.cell = newCell;
    }
    return self;
}

Another, cleaner, way to use a custom NSButtonCell subclass is shown here: Using full width of NSPopupButton for text, no arrows

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM