Created
January 15, 2019 13:14
-
-
Save jidolstar/606b6a6d5aa7f7377d94d22d163d91f3 to your computer and use it in GitHub Desktop.
bsReflection : objective-c
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
//Reflection | |
@interface bsReflection : NSObject | |
+(NSString*)stringFromClass:(Class)clazz; //클래스로부터 클래스 이름을 가져온다. | |
+(Class)classFromString:(NSString*)className; //클래스 이름으로부터 클래스를 가져온다. | |
+(Class)classFromObject:(id)object; //객체로부터 클래스를 가져온다. | |
+(NSString*)classNameFromObject:(id)object; //객체로부터 클래스 이름을 가져온다. | |
+(Class)getPropClassOfObject:(id)object key:(NSString*)key; //객체의 프로퍼티의 클래스를 가져온다. | |
+(Class)getPropClassOfClass:(Class)clazz key:(NSString*)key; //클래스의 프로퍼티의 클래스를 가져온다. | |
+(Class)getPropClassOfRootObject:(id)object keyPath:(NSString*)keyPath; //기반객체로부터 keyPath에 해당하는 속성의 클래스를 얻어온다. | |
+(Class)getPropClassOfRootClass:(Class)clazz keyPath:(NSString*)keyPath; //기반클래스로부터 keyPath에 해당하는 속성의 클래스를 얻어온다. | |
+(NSArray*)getPropNamesOfClass:(Class)clazz superInquiry:(BOOL)superInquiry; //클래스의 프로퍼티 이름을 배열로 가져온다. superInquiry는 해당클래스의 부모클래스 프로퍼티도 탐색할 것인지 결정하는 플래그다. | |
+(id)getPropValueOfObject:(id)object keyPath:(NSString*)keyPath; //객체에서 주어진 이름을 가진 프로퍼티의 값을 가져온다. | |
+(void)setPropValueOfObject:(id)object keyPath:(NSString*)keyPath value:(id)value; //객체에서 주어진 이름을 가진 프로퍼티의 값을 셋팅한다.(KVO, KVC에 적용안됨) | |
+(BOOL)hasPropAtObject:(id)object keyPath:(NSString*)keyPath; //객체에서 주어진 이름의 프로퍼티를 가지고 있는가? | |
+(BOOL)hasPropAtClass:(Class)clazz keyPath:(NSString*)keyPath; //클래스에서 주어진 이름의 프로퍼티를 가지고 있는가? | |
@end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import "bsReflection.h" | |
#import <objc/runtime.h> | |
#import <objc/message.h> | |
#import "bs.h" | |
@implementation bsReflection | |
//클래스로부터 클래스 이름을 가져온다. | |
+(NSString*)stringFromClass:(Class)clazz { | |
return NSStringFromClass( clazz ); | |
} | |
//클래스 이름으로부터 클래스를 가져온다. | |
+(Class)classFromString:(NSString*)className { | |
return NSClassFromString( className ); | |
} | |
//객체로부터 클래스를 가져온다. | |
+(Class)classFromObject:(id)object { | |
return [object class]; | |
} | |
//객체로부터 클래스 이름을 가져온다. | |
+(NSString*)classNameFromObject:(id)object { | |
return NSStringFromClass( [object class] ); | |
} | |
//객체의 프로퍼티의 클래스를 가져온다. | |
+(Class)getPropClassOfObject:(id)object key:(NSString*)key { | |
return [self getPropClassOfClass:[object class] key:key]; | |
} | |
//클래스의 프로퍼티의 클래스를 가져온다. | |
+(Class)getPropClassOfClass:(Class)clazz key:(NSString*)key { | |
const char *nm = [key UTF8String]; | |
objc_property_t p0 = class_getProperty( clazz, nm ); | |
if( p0 == NULL ) { | |
return NULL; | |
} | |
NSString *attr = [NSString stringWithFormat:@"%s", property_getAttributes( p0 )]; | |
NSArray *attrSplit = [attr componentsSeparatedByString:@"\""]; //"T@"NSString",R,V_test"에서 NSString만 추출해야 한다. | |
NSString *className = nil; | |
if ([attrSplit count] >= 2) { | |
className = [attrSplit objectAtIndex:1]; | |
} | |
if( className == nil ) return NULL; | |
return NSClassFromString( className ); | |
} | |
//기반객체로부터 keyPath에 해당하는 속성의 클래스를 얻어온다. | |
+(Class)getPropClassOfRootObject:(id)object keyPath:(NSString*)keyPath { | |
return [self getPropClassOfRootClass:[object class] keyPath:keyPath]; | |
} | |
//기반클래스로부터 keyPath에 해당하는 속성의 클래스를 얻어온다. | |
+(Class)getPropClassOfRootClass:(Class)clazz keyPath:(NSString*)keyPath { | |
NSArray *names = [bs strSplit:keyPath seperator:@"." trim:NO]; | |
if( [names count] == 0 ) return NULL; | |
__block Class c = clazz; | |
[names enumerateObjectsUsingBlock:^(NSString *nm, NSUInteger idx, BOOL *stop) { | |
objc_property_t p = class_getProperty(c, [nm UTF8String]); | |
if( !p ) { | |
*stop = YES; | |
return; | |
} | |
NSString *attr = [NSString stringWithFormat:@"%s", property_getAttributes( p )]; | |
NSArray *attrSplit = [attr componentsSeparatedByString:@"\""]; | |
if ( [attrSplit count] < 2) { | |
*stop = YES; | |
c = NULL; | |
} | |
NSString *className = [attrSplit objectAtIndex:1]; | |
c = NSClassFromString( className ); | |
}]; | |
return c; | |
} | |
//클래스의 프로퍼티 이름을 배열로 가져온다. superInquiry는 해당클래스의 부모클래스 프로퍼티도 탐색할 것인지 결정하는 플래그다. | |
+(NSArray*)getPropNamesOfClass:(Class)clazz superInquiry:(BOOL)superInquiry{ | |
if( clazz == NULL || clazz == [NSObject class] ) { | |
return nil; | |
} | |
NSMutableArray *r = [[NSMutableArray alloc] init]; | |
unsigned int count, i; | |
objc_property_t *ps = class_copyPropertyList( clazz, &count ); | |
for( i = 0; i < count; i++ ) { | |
objc_property_t p = ps[i]; | |
const char *pn = property_getName( p ); | |
if( pn ) { | |
[r addObject:[NSString stringWithUTF8String:pn]]; | |
} | |
} | |
free( ps ); | |
if( superInquiry ) { | |
NSArray *sr = [self getPropNamesOfClass:[clazz superclass] superInquiry:YES]; | |
if( sr != nil ) [r addObjectsFromArray:sr]; | |
} | |
return [NSArray arrayWithArray:r]; | |
} | |
//객체에서 주어진 이름을 가진 프로퍼티의 값을 가져온다. | |
+(id)getPropValueOfObject:(id)object keyPath:(NSString*)keyPath { | |
NSArray *t0 = [bs strSplit:keyPath seperator:@"." trim:NO]; | |
if( [t0 count] > 0 ) { | |
__block id t00 = object; | |
[t0 enumerateObjectsUsingBlock:^(NSString *name, NSUInteger idx, BOOL *stop) { | |
Ivar ivar = class_getInstanceVariable([t00 class], [[NSString stringWithFormat:@"_%@", name] UTF8String]); | |
t00 = object_getIvar( t00, ivar ); | |
if( t00 == nil ) *stop = YES; | |
}]; | |
return t00; | |
} | |
return nil; | |
} | |
//객체에서 주어진 이름을 가진 프로퍼티의 값을 셋팅한다.(KVO, KVC에 적용안됨) | |
+(void)setPropValueOfObject:(id)object keyPath:(NSString*)keyPath value:(id)value { | |
NSArray *t0 = [bs strSplit:keyPath seperator:@"." trim:NO]; | |
if( [t0 count] > 0 ) { | |
id t00 = object; | |
Ivar ivar = nil; | |
long i = 0, j = [t0 count]; | |
while( 1 ) { | |
ivar = class_getInstanceVariable([t00 class], [[NSString stringWithFormat:@"_%@", t0[i]] UTF8String]); | |
if( ++i < j ) { | |
t00 = object_getIvar( t00, ivar ); | |
if( t00 == nil ) break; | |
} else { | |
break; | |
} | |
} | |
object_setIvar( t00, ivar, value ); | |
} | |
} | |
//객체에서 주어진 이름의 프로퍼티를 가지고 있는가? | |
+(BOOL)hasPropAtObject:(id)object keyPath:(NSString*)keyPath { | |
return [self hasPropAtClass:[object class] keyPath:keyPath]; | |
} | |
//클래스에서 주어진 이름의 프로퍼티를 가지고 있는가? | |
+(BOOL)hasPropAtClass:(Class)clazz keyPath:(NSString*)keyPath { | |
//clazz와 name으로 캐싱필요! | |
NSArray *names = [bs strSplit:keyPath seperator:@"." trim:NO]; | |
if( [names count] == 0 ) return NO; | |
__block Class c = clazz; | |
__block BOOL has = NO; | |
NSUInteger maxIdx = [names count] - 1; | |
[names enumerateObjectsUsingBlock:^(NSString *nm, NSUInteger idx, BOOL *stop) { | |
objc_property_t p = class_getProperty(c, [nm UTF8String]); | |
if ( !p ) { | |
has = NO; | |
*stop = YES; | |
return; | |
} | |
if( idx == maxIdx ) { | |
has = YES; | |
return; | |
} | |
NSString *attr = [NSString stringWithFormat:@"%s", property_getAttributes( p )]; | |
NSArray *attrSplit = [attr componentsSeparatedByString:@"\""]; | |
if ( [attrSplit count] < 2) { | |
has = NO; | |
*stop = YES; | |
return; | |
} | |
NSString *className = [attrSplit objectAtIndex:1]; | |
c = NSClassFromString( className ); | |
}]; | |
return has; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment