Metoda opisu ogólnego Objective-C do drukowania wartości ivar

W Objective-C, powszechne jest nadpisywanie -description metodą, która wypisuje ID obiektu i nazwy zmiennych/wartości instancji. Chciałbym stworzyć ogólną metodę -description, która robi to poprzez introspekcję, a nie ręcznie robi to dla każdej klasy. Chciałbym żeby wyjście było coś takiego:

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

Byłoby również miło sortować według nazwy zmiennej instancji(więc zawsze są one w tej samej kolejności). Wreszcie, jeśli można to umieścić w kategorii bezpiecznie nadrzędnej NSObject funkcjonalność, która byłaby idealna (ale widzę, że nie jest to proste, ponieważ {[4] } ma ostrzeżenie o używaniu -[NSString stringWithFormat:] W -description).

Author: jrdioko, 2011-06-16

2 answers

To jest świetne pytanie! Ponieważ nie znalazłem czegoś takiego, napisałem małą funkcję, która robi to za Ciebie. Zastępuje - (NSString *)description z NSObject metodą swizzling (yes, I ' m this evil. Mahahahahahahahahahahaha) i drukuje ivar w kolejności, w jakiej pojawiają się również w klasie (można je łatwo edytować, aby wyświetlić je w kolejności alfabetycznej).

NIE! zapomnij zadzwonić NSObjectSwizzleDescription()!

.plik h:

@interface NSObject (JSObjectAdditions)
@end


void NSObjectSwizzleDescription();

.plik 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);
}
 13
Author: JustSid,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-01-11 19:27:10

Nie znam żadnego kodu robiącego to, ale jeśli to istnieje, byłbym zainteresowany w celach debugowania!

Dziwię się, że nie znalazłem jeszcze czegoś takiego, klasyczne techniki po prostu działają, ale rzeczywiście byłoby miło mieć jakąś metodę inspect, która jest, jak sądzę, możliwa za pomocą refleksji, ale może się mylę.

Proponuję rzucić okiem na ten ciekawy post , który jest związany z tym, czego szukasz, i może być podstawą do wdrożenia to.

Kolejną ciekawą rzeczą jest również NSLogger , który jest fajnym narzędziem do debugowania.

 1
Author: Vincent Guerci,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:53:09