Gibt es eine integrierte Methode, Funktion, API, allgemein akzeptierte Methode usw., um den Inhalt eines instanziierten Objekts in Objective-C zu sichern, insbesondere in Apples Cocoa / Cocoa-Touch-Umgebung?
Ich möchte in der Lage sein, so etwas zu tun
MyType *the_thing = [[MyType alloc] init];
NSString *the_dump = [the_thing dump]; //pseudo code
NSLog("Dumped Contents: %@", the_dump);
Außerdem werden die Namen und Werte der Instanzvariablen des Objekts sowie alle Methoden angezeigt, die zur Laufzeit aufgerufen werden können. Idealerweise in einem leicht lesbaren Format.
Für Entwickler, die mit PHP vertraut sind, suche ich grundsätzlich nach dem Äquivalent der Reflektionsfunktionen ( var_dump()
, get_class_methods()
) und der OO Reflection API.
objective-c
cocoa
xcode
reflection
introspection
Alan Storm
quelle
quelle
Antworten:
UPDATE: Jeder, der solche Dinge tun möchte, sollte sich den ObjC-Wrapper von Mike Ash für die Objective-C-Laufzeit ansehen .
So würden Sie mehr oder weniger vorgehen:
#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); }
Von dort aus ist es einfach, die tatsächlichen Werte der Eigenschaften einer Instanz abzurufen, aber Sie müssen überprüfen, ob es sich um primitive Typen oder Objekte handelt. Daher war ich zu faul, um sie einzufügen. Sie können auch die Vererbungskette scannen Ruft alle für ein Objekt definierten Eigenschaften ab. Dann gibt es Methoden, die für Kategorien definiert sind, und mehr ... Aber fast alles ist leicht verfügbar.
Hier ist ein Auszug dessen, was der obige Code für UILabel ausgibt:
{ 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 ); }
quelle
NSObject
Kategorie). Sie müssen jedochfree()
Ihreivars
,properties
undmethods
Arrays, oder Sie lecken sie.description
Ohne die Methode (wie .toString () in Java) habe ich noch nichts von einer eingebauten Methode gehört, aber es wäre nicht allzu schwierig, eine zu erstellen. Die Objective-C-Laufzeitreferenz enthält eine Reihe von Funktionen, mit denen Sie Informationen zu Instanzvariablen, Methoden, Eigenschaften usw. eines Objekts abrufen können.quelle
Folgendes wird derzeit verwendet, um Klassenvariablen automatisch in einer Bibliothek für eine spätere öffentliche Veröffentlichung zu drucken. Dabei werden alle Eigenschaften der Instanzklasse bis zum Ende des Vererbungsbaums gesichert. Dank KVC müssen Sie sich nicht darum kümmern, ob eine Eigenschaft ein primitiver Typ ist oder nicht (für die meisten Typen).
// 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]]]; }
quelle
Ich habe ein paar Änderungen an Kendalls Code zum Drucken von Eigenschaftswerten vorgenommen, was für mich sehr praktisch war. Ich habe es als Instanzmethode anstelle einer Klassenmethode definiert, wie es die Superklassenrekursion so nennt. Ich habe auch die Ausnahmebehandlung für nicht KVO-kompatible Eigenschaften hinzugefügt und der Ausgabe Zeilenumbrüche hinzugefügt, um das Lesen (und Diff) zu vereinfachen:
-(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; }
quelle
Ehrlich gesagt ist das richtige Tool für diesen Job der Debugger von Xcode. All diese Informationen sind auf visuelle Weise leicht zugänglich. Nehmen Sie sich Zeit, um zu lernen, wie man es benutzt. Es ist ein wirklich mächtiges Werkzeug.
Mehr Informationen:
Verwenden des Debuggers
Veraltetes Xcode-Debugging-Handbuch - von Apple archiviert
Informationen zum Debuggen mit Xcode - von Apple archiviert
Über LLDB und Debugging - archiviert von Apple
Debuggen mit GDB - von Apple archiviert
SpriteKit Debugging Guide - von Apple archiviert
Debuggen von Programmierthemen für Core Foundation - archiviert von Apple
quelle
Ich habe daraus einen Cocoapod gemacht, https://github.com/neoneye/autodescribe
Ich habe den Code von Christopher Pickslay geändert und ihn zu einer Kategorie in NSObject gemacht und ihm auch eine Unittest hinzugefügt. So verwenden Sie es:
@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
quelle
Ich bin vorher mit Introspektion und Refektion verwechselt, also holen Sie sich unten einige Informationen.
Introspektion ist die Fähigkeit des Objekts, zu überprüfen, um welchen Typ es sich handelt, welches Protokoll es entspricht oder welchen Selektor es beantworten kann. Die objc api wie
isKindOfClass
/isMemberOfClass
/conformsToProtocol
/respondsToSelector
etc.Die Refektionsfähigkeit ist weiter als die Introspektion. Sie kann nicht nur Objektinformationen abrufen, sondern auch Objektmetadaten, -eigenschaften und -funktionen bedienen. wie
object_setClass
kann Objekttyp ändern.quelle