2014-12-06 1 views
1

객체의 인스턴스를 해당 객체 클래스의 하위 클래스 인스턴스로 변환하여 해당 객체 클래스의 추가 메서드와 속성을 사용할 수있게하려고합니다. Objective-C에서 하위 클래스Objective-C의 하위 클래스 인스턴스로 객체 변환 (또는 복사)

복사 방법에서 해당 개체 클래스의 속성을 하드 코딩 할 필요가없는 방식으로이 작업을 수행하려면 어떻게해야합니까?

+1

, 아니, 그렇게 할 수있는 방법이 없다 . 아래에서 제안하는 구성표는 일부 개체에 대해서는 작동하지만 절대적으로 멀리 떨어져 있으므로 원본 및 대상 클래스가 모든 중요한 설정을 설정 가능한 속성으로 "노출"하는지주의 깊게 확인한 경우에만 "프로덕션"코드에서 사용해야합니다. –

답변

4

Objective-C에서 개체를 하위 클래스의 인스턴스로 변환 할 수 없습니다. 그러나 아래 클래스를 사용하면 객체와 하위 클래스의 인스턴스를 제공하고 모든 속성의 값을 하위 클래스 인스턴스에 복사 할 수 있습니다. 이 구현은 Objective-C 객체 유형과 C 기본형 모두에서 작동합니다. 중요한 변수를 볼 수 있고 설정할 수 있다는 것을 알고 있으면 복사해야 할 속성을 지정 (또는 실제로 결정) 할 필요가 없습니다 (즉, "읽기 전용"으로 표시되거나 표시되지 않는 속성이 없음). 노출 값은 클래스에서 다시 계산할 수 없습니다). 따라서이 메소드는 알려진 클래스에 대해 상대적으로 강력하며이 매개 변수에 맞는 객체 클래스에서 향후 변경 사항을 지원하기 위해 업데이트 할 필요가 없습니다. iOS 8과 호환됩니다. subclassObject에

+ (id) copyObject:(id)object toSubclassObject:(id)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 
1

은 내가 NSTableView에 사용 NSTextFieldCell의 서브 클래스를 만드는 데 필요한, 셀에 설정 한 그대로의 속성을 유지하고 싶어 인터페이스 빌더.

나는 개체의 속성을 저장하고 복원하기 위해 만들어진 NSKeyedArchiver을 사용하여 작업을 해결했습니다. NSTextFieldCell이 initWithCoder를 구현

때문에,이 아카이브 기능을 지원, 따라서 나는의 다른 속성에서 내 서브 클래스를 초기화하기 위해서이 코드를 사용할 수 있습니다 일반적으로

- (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; 
} 
관련 문제