Есть ли встроенный метод, функция, API, общепринятый способ и т. Д. Для сброса содержимого созданного объекта в Objective-C, особенно в среде Apple Cocoa / Cocoa-Touch?
Я хочу сделать что-то вроде
MyType *the_thing = [[MyType alloc] init];
NSString *the_dump = [the_thing dump]; //pseudo code
NSLog("Dumped Contents: %@", the_dump);
и отображать имена и значения переменных экземпляра объекта, а также любые методы, доступные для вызова во время выполнения. В идеале в удобном для чтения формате.
Для разработчиков, знакомых с PHP, я в основном ищу эквивалент функций отражения ( var_dump()
, get_class_methods()
) и OO Reflection API.
objective-c
cocoa
xcode
reflection
introspection
Алан Сторм
источник
источник
Ответы:
ОБНОВЛЕНИЕ: Любой, кто хочет заниматься подобными вещами, может захотеть проверить оболочку ObjC Майка Эша для среды выполнения Objective-C .
Вот как бы вы это сделали:
#import <objc/runtime.h> . . . -(void)dumpInfo { Class clazz = [self class]; u_int count; Ivar* ivars = class_copyIvarList(clazz, &count); NSMutableArray* ivarArray = [NSMutableArray arrayWithCapacity:count]; for (int i = 0; i < count ; i++) { const char* ivarName = ivar_getName(ivars[i]); [ivarArray addObject:[NSString stringWithCString:ivarName encoding:NSUTF8StringEncoding]]; } free(ivars); objc_property_t* properties = class_copyPropertyList(clazz, &count); NSMutableArray* propertyArray = [NSMutableArray arrayWithCapacity:count]; for (int i = 0; i < count ; i++) { const char* propertyName = property_getName(properties[i]); [propertyArray addObject:[NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding]]; } free(properties); Method* methods = class_copyMethodList(clazz, &count); NSMutableArray* methodArray = [NSMutableArray arrayWithCapacity:count]; for (int i = 0; i < count ; i++) { SEL selector = method_getName(methods[i]); const char* methodName = sel_getName(selector); [methodArray addObject:[NSString stringWithCString:methodName encoding:NSUTF8StringEncoding]]; } free(methods); NSDictionary* classDump = [NSDictionary dictionaryWithObjectsAndKeys: ivarArray, @"ivars", propertyArray, @"properties", methodArray, @"methods", nil]; NSLog(@"%@", classDump); }
Оттуда легко получить фактические значения свойств экземпляра, но вы должны проверить, являются ли они примитивными типами или объектами, поэтому мне было лень вставлять его. Вы также можете выбрать сканирование цепочки наследования, чтобы получить все свойства, определенные для объекта. Затем есть методы, определенные по категориям, и многое другое ... Но почти все доступно.
Вот отрывок из того, что приведенный выше код сбрасывает для UILabel:
{ ivars = ( "_size", "_text", "_color", "_highlightedColor", "_shadowColor", "_font", "_shadowOffset", "_minFontSize", "_actualFontSize", "_numberOfLines", "_lastLineBaseline", "_lineSpacing", "_textLabelFlags" ); methods = ( rawSize, "setRawSize:", "drawContentsInRect:", "textRectForBounds:", "textSizeForWidth:", . . . ); properties = ( text, font, textColor, shadowColor, shadowOffset, textAlignment, lineBreakMode, highlightedTextColor, highlighted, enabled, numberOfLines, adjustsFontSizeToFitWidth, minimumFontSize, baselineAdjustment, "_lastLineBaseline", lineSpacing, userInteractionEnabled ); }
источник
NSObject
категорией). Однако у вас естьfree()
своиivars
,properties
иmethods
массивы, иначе вы их просочите.Короткие от
description
метода (как .ToString () в Java), я не слышал , тот , который был построен в, но это не было бы слишком трудно создать. В Objective-C Runtime Reference есть набор функций, которые вы можете использовать для получения информации о переменных экземпляра объекта, методах, свойствах и т. Д.источник
Вот то, что я сейчас использую для автоматической печати переменных класса в библиотеке для возможного общедоступного выпуска - он работает путем полного сброса всех свойств из класса экземпляра до дерева наследования. Благодаря KVC вам не нужно заботиться о том, является ли свойство примитивным типом или нет (для большинства типов).
// Finds all properties of an object, and prints each one out as part of a string describing the class. + (NSString *) autoDescribe:(id)instance classType:(Class)classType { NSUInteger count; objc_property_t *propList = class_copyPropertyList(classType, &count); NSMutableString *propPrint = [NSMutableString string]; for ( int i = 0; i < count; i++ ) { objc_property_t property = propList[i]; const char *propName = property_getName(property); NSString *propNameString =[NSString stringWithCString:propName encoding:NSASCIIStringEncoding]; if(propName) { id value = [instance valueForKey:propNameString]; [propPrint appendString:[NSString stringWithFormat:@"%@=%@ ; ", propNameString, value]]; } } free(propList); // Now see if we need to map any superclasses as well. Class superClass = class_getSuperclass( classType ); if ( superClass != nil && ! [superClass isEqual:[NSObject class]] ) { NSString *superString = [self autoDescribe:instance classType:superClass]; [propPrint appendString:superString]; } return propPrint; } + (NSString *) autoDescribe:(id)instance { NSString *headerString = [NSString stringWithFormat:@"%@:%p:: ",[instance class], instance]; return [headerString stringByAppendingString:[self autoDescribe:instance classType:[instance class]]]; }
источник
Я сделал пару настроек в коде Кендалла для печати значений свойств, которые мне очень пригодились. Я определил его как метод экземпляра, а не как метод класса, как его вызывает рекурсия суперкласса. Я также добавил обработку исключений для свойств, не совместимых с KVO, и добавил разрывы строк в вывод, чтобы упростить чтение (и различие):
-(NSString *) autoDescribe:(id)instance classType:(Class)classType { NSUInteger count; objc_property_t *propList = class_copyPropertyList(classType, &count); NSMutableString *propPrint = [NSMutableString string]; for ( int i = 0; i < count; i++ ) { objc_property_t property = propList[i]; const char *propName = property_getName(property); NSString *propNameString =[NSString stringWithCString:propName encoding:NSASCIIStringEncoding]; if(propName) { @try { id value = [instance valueForKey:propNameString]; [propPrint appendString:[NSString stringWithFormat:@"%@=%@\n", propNameString, value]]; } @catch (NSException *exception) { [propPrint appendString:[NSString stringWithFormat:@"Can't get value for property %@ through KVO\n", propNameString]]; } } } free(propList); // Now see if we need to map any superclasses as well. Class superClass = class_getSuperclass( classType ); if ( superClass != nil && ! [superClass isEqual:[NSObject class]] ) { NSString *superString = [self autoDescribe:instance classType:superClass]; [propPrint appendString:superString]; } return propPrint; }
источник
Честно говоря, правильный инструмент для этой работы - отладчик Xcode. Вся эта информация легко доступна визуально. Найдите время, чтобы узнать, как им пользоваться, это действительно мощный инструмент.
Больше информации:
Использование отладчика
Устаревшее руководство по отладке Xcode - архивировано Apple
Об отладке с помощью Xcode - в архиве Apple
О LLDB и отладке - в архиве Apple
Отладка с GDB - в архиве Apple
Руководство по отладке SpriteKit - архивировано Apple
Темы отладки программирования для Core Foundation - в архиве Apple
источник
Я сделал из этого cocoapod, https://github.com/neoneye/autodescribe
Я изменил код Кристофера Пикслея и сделал его категорией в NSObject, а также добавил к нему unittest. Вот как им пользоваться:
@interface TestPerson : NSObject @property (nonatomic, strong) NSString *firstName; @property (nonatomic, strong) NSString *lastName; @property (nonatomic, strong) NSNumber *age; @end @implementation TestPerson // empty @end @implementation NSObject_AutoDescribeTests -(void)test0 { TestPerson *person = [TestPerson new]; person.firstName = @"John"; person.lastName = @"Doe"; person.age = [NSNumber numberWithFloat:33.33]; NSString *actual = [person autoDescribe]; NSString *expected = @"firstName=John\nlastName=Doe\nage=33.33"; STAssertEqualObjects(actual, expected, nil); } @end
источник
Раньше меня путали с интроспекцией и рефлексией, поэтому получите некоторую информацию ниже.
Самоанализ - это способность объекта проверить, какой он тип, или протокол, которому он соответствует, или селектор, на который он может ответить. API objc, например
isKindOfClass
/isMemberOfClass
/conformsToProtocol
/respondsToSelector
и т. Д.Возможность отражения - это не только самоанализ , Он не только может получать информацию об объекте, но также может управлять метаданными, свойствами и функциями объекта. например,
object_setClass
может изменять тип объекта.источник