2011-06-16 16 views
9

Objective-C'de, nesne kimliğini ve örnek değişken adlarını/değerlerini yazdıran bir yöntemle -description geçersiz kılmak yaygındır. Her sınıf için bunu manuel olarak yapmak yerine, iç gözlem yoluyla bunu yapan genel bir -description yöntemi yapmak istiyorum. Ayrıca örnek değişken adı göre sıralamak için iyi olurduIvar değerlerini yazdırmak için Genel Hedef-C açıklama yöntemi

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

(böylece aynı sırada her zaman): Ben bir şey gibi olmak çıkışını istiyorum. Son olarak, bu, NSObject işlevini güvenli bir şekilde geçersiz kılan bir kategoriye konabilirse, bu mükemmel olur (ancak NSObject.m'un -description numaralı telefonunda -[NSString stringWithFormat:] kullanımıyla ilgili bir uyarısı olduğundan bunun kolay olmadığını görüyorum).

cevap

12

Bu harika bir soru! Böyle bir şey bulamadığım için, bunu sizin için yapan küçük bir işlev yazdım. Yöntem swizzling (evet, ben bu kötülük. MAHAHAHAHAHahahahaha) kullanarak - (NSString *)descriptionNSObject değiştirir ve sınıfta da görünebilir sırayla ivar yazdırır (bunları alfabetik sırayla görüntülemek için kolayca düzenleyebilirsiniz).

YAPMAYIN! NSObjectSwizzleDescription()'u aramayı unutma!

.h dosyası:

@interface NSObject (JSObjectAdditions) 
@end 


void NSObjectSwizzleDescription(); 

.m dosyası: kelime için

#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

+0

+1 ve müthiş "swizzling". Tüm dizeleri bir "NSMutableArray" öğesine ekleyip '[array componentsJoinedByString: @" "] döndürme işlemi, NSMutableString'in" appendFormat "değeri *" O (n^2) "olmasına rağmen performansı düşürerek performansı biraz artırır. kritik. – orip

1

Bunu yapan herhangi bir kod bilmiyorum, ancak eğer varsa, hata ayıklama amaçları ile ilgilenirim!

Henüz böyle bir şey bulamadım şaşırdım, classic techniques sadece çalışır, ama gerçekten yansıma kullanarak düşünüyorum, belki de inspect yönteminin bir çeşit olması güzel olurdu, ama belki ben ' m yanlış.

Aradığınızı tam olarak anlatan bir a this interesting post göz atmanızı öneririz ve bunu uygulamak için bir temel olabilir.

Bir başka ilginç şey de hata ayıklama için güzel bir araç olan NSLogger.