2011-06-16 57 views
9

在Objective-C中,通常用打印对象ID和实例变量名称/值的方法覆盖-description。我想制作一个通用的-description方法,通过内省来完成此操作,而不是手动为每个类执行此操作。我想输出是这样的:打印伊娃值的通用Objective-C描述方法

<ClassName: 0x??????, ivar1: value1, ivar2: value2, ivar3: value3, ...> 

这也将是不错的实例变量名称排序(所以他们总是以相同的顺序)。最后,如果这可以安全地覆盖NSObject功能,那将是完美的(但我认为这并不简单,因为NSObject.m-description中有关于使用-[NSString stringWithFormat:]的警告)。

回答

12

这是一个很好的问题!因为我还没有找到这样的东西,所以我写了一个小功能为你做这个。它会用NSObjectNSObject替换NSObject使用方法swizzling(是的,我是这个邪恶的MAHAHAHAHAHahahahaha),并按他们也出现在课堂上的顺序打印伊娃(你可以轻松编辑它们以按字母顺序显示)。

不要!忘记拨打NSObjectSwizzleDescription()

.h文件中:

@interface NSObject (JSObjectAdditions) 
@end 


void NSObjectSwizzleDescription(); 

.m文件:

#import <objc/objc.h> 
#import "JSObject.h" 

@implementation NSObject (JSObjectAdditions) 

- (NSString *)verboseDescription 
{ 
    NSMutableString *description = [NSMutableString stringWithFormat:@"<%@: %p>", NSStringFromClass([self class]), self]; 

    uint32_t ivarCount; 
    Ivar *ivars = class_copyIvarList([self class], &ivarCount); 

    if(ivars) 
    { 
     [description appendString:@"\n{"]; 

     for(uint32_t i=0; i<ivarCount; i++) 
     { 
      Ivar ivar = ivars[i]; 
      const char *ivarType = ivar_getTypeEncoding(ivar); 
      id ivarObject = object_getIvar(self, ivar); 

      [description appendFormat:@"\n %s: ", ivar_getName(ivar)]; 

      // Default signed data types 
      if(strcmp(ivarType, "c") == 0) 
      { 
       char character = (char)ivarObject; 
       [description appendFormat:@"'%c'", character]; 
      } 
      else if(strcmp(ivarType, "i") == 0 || strcmp(ivarType, "l") == 0) // l is also 32 bit in the 64 bit runtime environment 
      { 
       int integer = (int)ivarObject; 
       [description appendFormat:@"%i", integer]; 
      } 
      else if(strcmp(ivarType, "s") == 0) 
      { 
       short shortVal = (short)ivarObject; 
       [description appendFormat:@"%i", (int)shortVal]; 
      } 
      else if(strcmp(ivarType, "q") == 0) 
      { 
       long long longVal = (long long)ivarObject; 
       [description appendFormat:@"%l", longVal]; 
      } 
      // Default unsigned data types 
      else if(strcmp(ivarType, "C") == 0) 
      { 
       unsigned char chracter = (unsigned char)ivarObject; 
       [description appendFormat:@"'%c'", chracter]; 
      } 
      else if(strcmp(ivarType, "I") == 0 || strcmp(ivarType, "L") == 0) 
      { 
       unsigned int integer = (unsigned int)ivarObject; 
       [description appendFormat:@"%u", integer]; 
      } 
      else if(strcmp(ivarType, "S") == 0) 
      { 
       unsigned short shortVal = (unsigned short)ivarObject; 
       [description appendFormat:@"%i", (int)shortVal]; 
      } 
      else if(strcmp(ivarType, "Q") == 0) 
      { 
       unsigned long long longVal = (unsigned long long)ivarObject; 
       [description appendFormat:@"%ll", longVal]; 
      } 
      // Floats'n'stuff 
      else if(strcmp(ivarType, "f") == 0) 
      { 
       float floatVal; 
       memcpy(&floatVal, &ivarObject, sizeof(float)); 

       [description appendFormat:@"%f", floatVal]; 
      } 
      else if(strcmp(ivarType, "d") == 0) 
      { 
       double doubleVal; 
       memcpy(&doubleVal, &ivarObject, sizeof(double)); 

       [description appendFormat:@"%f", doubleVal]; 
      } 
      // Boolean and pointer 
      else if(strcmp(ivarType, "B") == 0) 
      { 
       BOOL booleanVal = (BOOL)ivarObject; 
       [description appendFormat:@"%@", (booleanVal ? @"YES" : @"NO")]; 
      } 
      else if(strcmp(ivarType, "v") == 0) 
      { 
       void *pointer = (void *)ivarObject; 
       [description appendFormat:@"%p", pointer]; 
      } 
      else if(strcmp(ivarType, "*") == 0 || strcmp(ivarType, ":") == 0) // SEL is just a typecast for a cstring 
      { 
       char *cstring = (char *)ivarObject; 
       [description appendFormat:@"\"%s\"", cstring]; 
      } 
      else if(strncmp(ivarType, "@", 1) == 0) 
      { 
       [description appendFormat:@"%@", ivarObject]; 
      } 
      else if(strcmp(ivarType, "#") == 0) 
      { 
       Class objcClass = (Class)ivarObject; 
       [description appendFormat:@"%s", class_getName(objcClass)]; 
      } 
      else 
       [description appendString:@"???"]; 
     } 

     [description appendString:@"\n}"]; 
     free(ivars); 
    } 

    return description; 
} 

@end 


void NSObjectSwizzleDescription() 
{ 
    Method origMethod = class_getInstanceMethod([NSObject class], @selector(description)); 
    Method newMethod = class_getInstanceMethod([NSObject class], @selector(verboseDescription)); 

    method_exchangeImplementations(origMethod, newMethod); 
} 
+0

+1单词 “混写” – jrdioko 2011-06-16 20:28:03

+0

+1,真棒。尽管NSMutableString的appendFormat是* not *'O(n^2)',所以将所有字符串追加到'NSMutableArray'并返回'[array componentsJoinedByString:@“”]'会通过保存分配来提高性能危急。 – orip 2013-01-07 09:55:44

1

我不知道这样做的任何代码,但如果存在,我会对调试目的感兴趣!

我很惊讶我还没有找到像这样的东西,classic techniques只是工作,但它确实很高兴有某种inspect方法,这是我认为,可能使用反射,但也许我'米错了。

我建议看看a this interesting post,这与您正在寻找的内容有关,并且可能是实施它的基础。

另一个有趣的事情是NSLogger,这是一个很好的调试工具。