객체의 인스턴스를 해당 객체 클래스의 하위 클래스 인스턴스로 변환하여 해당 객체 클래스의 추가 메서드와 속성을 사용할 수있게하려고합니다. Objective-C에서 하위 클래스Objective-C의 하위 클래스 인스턴스로 객체 변환 (또는 복사)
복사 방법에서 해당 개체 클래스의 속성을 하드 코딩 할 필요가없는 방식으로이 작업을 수행하려면 어떻게해야합니까?
객체의 인스턴스를 해당 객체 클래스의 하위 클래스 인스턴스로 변환하여 해당 객체 클래스의 추가 메서드와 속성을 사용할 수있게하려고합니다. Objective-C에서 하위 클래스Objective-C의 하위 클래스 인스턴스로 객체 변환 (또는 복사)
복사 방법에서 해당 개체 클래스의 속성을 하드 코딩 할 필요가없는 방식으로이 작업을 수행하려면 어떻게해야합니까?
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
은 내가 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;
}
, 아니, 그렇게 할 수있는 방법이 없다 . 아래에서 제안하는 구성표는 일부 개체에 대해서는 작동하지만 절대적으로 멀리 떨어져 있으므로 원본 및 대상 클래스가 모든 중요한 설정을 설정 가능한 속성으로 "노출"하는지주의 깊게 확인한 경우에만 "프로덕션"코드에서 사용해야합니다. –