繁体   English   中英

将对象转换(或复制)到Objective-C中的子类实例

[英]Transform (or copy) an object to a subclass instance in Objective-C

我想将一个对象的实例转换为该对象类的子类的实例,以便我可以在Objective-C中使用该子类的其他方法和属性。

如何以不需要在复制方法中对该对象类的属性进行硬编码的方式执行此操作?

在Objective-C中无法将对象转换为子类的实例。 但是,使用下面的类,您可以提供对象和子类的实例,并将所有属性的值复制到子类实例。 此实现适用于Objective-C对象类型和C基元。 您不必指定(或实际上确定)需要复制的属性,只要您知道重要变量是可见的并且可以设置(即,没有属性显示为“只读”或不暴露,其价值不能由班级重新计算)。 因此,对于已知类,此方法相对健壮,并且不需要更新以支持您在对象类中进行的适合这些参数的更改。 它与iOS 8兼容。

该类提供了四种类方法:

+ (id) copyObject:(id)object toSubclassObject:(id)subclassObject

将对象的所有属性复制到subclassObject。 如果subclassObject不是object的子类,则返回nil。

+ (NSDictionary *) propertiesOfObject:(id)object;

返回对象的所有可见属性的字典,包括来自其所有超类(NSObject除外)的字典。

+ (NSDictionary *) propertiesOfClass:(Class)class;

返回类的所有可见属性的字典,包括来自其所有超类(NSObject除外)的字典。

+ (NSDictionary *) propertiesOfSubclass:(Class)class;

返回特定于子类的所有可见属性的字典。 包括其超类的属性。

标题:

//  SYNUtilities.h

#import <Foundation/Foundation.h>

@interface SYNUtilities : NSObject
+ (id) copyObject:(id)object toSubclassObject:(id)subclassObject;
+ (NSDictionary *) propertiesOfObject:(id)object;
+ (NSDictionary *) propertiesOfClass:(Class)class;
+ (NSDictionary *) propertiesOfSubclass:(Class)class;
@end

执行:

#import "SYNUtilities.h"
#import <objc/runtime.h>
#import <objc/message.h>

@implementation SYNUtilities
+ (id) copyObject:(id)object toSubclassObject:(id)subclassObject
{
    if (![[subclassObject class] isSubclassOfClass:[object class]]) {
        return nil;
    }

    NSDictionary * properties = [self propertiesOfObject:object];
    NSLog(@"Properties of %@:\n%@", [object class], properties);

    for (NSString * property in properties) {
        SEL selector = NSSelectorFromString(property);
        if (selector) {
            id value = [object valueForKey:property];
            [subclassObject setValue:value forKey:property];
        }
    }
    return subclassObject;
}

+ (NSDictionary *) propertiesOfObject:(id)object
{
    Class class = [object class];
    return [self propertiesOfClass:class];
}

+ (NSDictionary *) propertiesOfClass:(Class)class
{
     if (class == NULL) {
        return nil;
    }

   NSMutableDictionary * properties = [NSMutableDictionary dictionary];
    [self propertiesForHierarchyOfClass:class onDictionary:properties];
    return [NSDictionary dictionaryWithDictionary:properties];
}

+ (NSDictionary *) propertiesOfSubclass:(Class)class
{
    if (class == NULL) {
        return nil;
    }

    NSMutableDictionary *properties = [NSMutableDictionary dictionary];
    return [self propertiesForSubclass:class onDictionary:properties];
}

+ (NSMutableDictionary *)propertiesForHierarchyOfClass:(Class)class onDictionary:(NSMutableDictionary *)properties
{
    if (class == NULL) {
        return nil;
    }

    if (class == [NSObject class]) {
        // On reaching the NSObject base class, return all properties collected.
        return properties;
    }

    // Collect properties from the current class.
    [self propertiesForSubclass:class onDictionary:properties];

    // Collect properties from the superclass.
    return [self propertiesForHierarchyOfClass:[class superclass] onDictionary:properties];
}

+ (NSMutableDictionary *) propertiesForSubclass:(Class)class onDictionary:(NSMutableDictionary *)properties
{
    unsigned int outCount, i;
    objc_property_t *objcProperties = class_copyPropertyList(class, &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = objcProperties[i];
        const char *propName = property_getName(property);
        if(propName) {
            const char *propType = getPropertyType(property);
            NSString *propertyName = [NSString stringWithUTF8String:propName];
            NSString *propertyType = [NSString stringWithUTF8String:propType];
            [properties setObject:propertyType forKey:propertyName];
        }
    }
    free(objcProperties);

    return properties;
}

static const char *getPropertyType(objc_property_t property) {
    const char *attributes = property_getAttributes(property);
    char buffer[1 + strlen(attributes)];
    strcpy(buffer, attributes);
    char *state = buffer, *attribute;
    while ((attribute = strsep(&state, ",")) != NULL) {
        if (attribute[0] == 'T' && attribute[1] != '@') {
            // A C primitive type:
            /*
             For example, int "i", long "l", unsigned "I", struct.
             Apple docs list plenty of examples of values returned. For a list
             of what will be returned for these primitives, search online for
             "Objective-c" "Property Attribute Description Examples"
             */
            NSString *name = [[NSString alloc] initWithBytes:attribute + 1 length:strlen(attribute) - 1 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
        else if (attribute[0] == 'T' && attribute[1] == '@' && strlen(attribute) == 2) {
            // An Objective C id type:
            return "id";
        }
        else if (attribute[0] == 'T' && attribute[1] == '@') {
            // Another Objective C id type:
            NSString *name = [[NSString alloc] initWithBytes:attribute + 3 length:strlen(attribute) - 4 encoding:NSASCIIStringEncoding];
            return (const char *)[name cStringUsingEncoding:NSASCIIStringEncoding];
        }
    }
    return "";
}

@end

我需要创建NSTextFieldCell的子类,在NSTableView ,并希望保持在Interface Builder中为单元格设置的完整属性。

我通过使用NSKeyedArchiver解决了这个任务, NSKeyedArchiver用于存储和恢复对象的属性。

由于NSTextFieldCell实现了initWithCoder,它支持archiver函数,因此我可以使用此代码从其他属性初始化我的子类:

- (id)initWithCell:(NSCell *)cell {
    // Use NSArchiver to copy the NSCell's properties into our subclass
    NSMutableData *data = [NSMutableData data];
    NSKeyedArchiver *arch = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
    [cell encodeWithCoder:arch];
    [arch finishEncoding];
    NSKeyedUnarchiver *ua = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
    self = [self initWithCoder:ua];
    // Here I'd set up additional properties of my own class
    return self;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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