是否有一种方法来记录Objective-C实例的所有属性值

时间:2021-01-31 22:46:42

I was just wondering if there is a quick and easy way of printing out to the log all of the various values of the properties to my class for debugging purposes. Like I would like to know what the values of all of the BOOLs, floats, etc. are.

我只是想知道是否有一种快速简便的方法将所有属性的值打印到日志中,以便调试。我想知道所有的BOOLs, float等的值是多少。

4 个解决方案

#1


24  

This question seems the have the answer to your question.

这个问题似乎是你问题的答案。

Update:

I got curious and made a catagory:

我很好奇,于是做了个问答:

//Using Xcode 4.5.2 - iOS 6 - LLDB - Automatic Reference Counting

//NSObject+logProperties.h    
@interface NSObject (logProperties)
- (void) logProperties;
@end

//NSObject+logProperties.m
#import "NSObject+logProperties.h"
#import <objc/runtime.h>

@implementation NSObject (logProperties)

- (void) logProperties {

    NSLog(@"----------------------------------------------- Properties for object %@", self);

    @autoreleasepool {
        unsigned int numberOfProperties = 0;
        objc_property_t *propertyArray = class_copyPropertyList([self class], &numberOfProperties);
        for (NSUInteger i = 0; i < numberOfProperties; i++) {
            objc_property_t property = propertyArray[i];
            NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)];
            NSLog(@"Property %@ Value: %@", name, [self valueForKey:name]);
        }
        free(propertyArray);
    }    
    NSLog(@"-----------------------------------------------");
}

@end

Include it in your class: #import "NSObject+logProperties.h"

在你的类中包含它:#import "NSObject+logProperties.h"

and call [self logProperties]; to those properties!

并调用(自我logProperties);这些属性!

#2


5  

The current answers just show how to do it for properties. If you want every instance variable printed out you could do something like the below.

当前的答案只是显示如何对属性进行处理。如果您想打印出每个实例变量,您可以做如下操作。

- (void)logAllProperties {
    unsigned int count;
    Ivar *ivars = class_copyIvarList([self class], &count);
    for (unsigned int i = 0; i < count; i++) {
        Ivar ivar = ivars[i];

        const char *name = ivar_getName(ivar);
        const char *type = ivar_getTypeEncoding(ivar);
        ptrdiff_t offset = ivar_getOffset(ivar);

        if (strncmp(type, "i", 1) == 0) {
            int intValue = *(int*)((uintptr_t)self + offset);
            NSLog(@"%s = %i", name, intValue);
        } else if (strncmp(type, "f", 1) == 0) {
            float floatValue = *(float*)((uintptr_t)self + offset);
            NSLog(@"%s = %f", name, floatValue);
        } else if (strncmp(type, "@", 1) == 0) {
            id value = object_getIvar(self, ivar);
            NSLog(@"%s = %@", name, value);
        }
        // And the rest for other type encodings
    }
    free(ivars);
}

Although I wouldn't particularly suggest doing this in practice, but if it's for debug purposes then that's fine. You could implement this as a category on NSObject and keep it lying around for use when debugging. If completed for all type encodings then it could make for a very nice little method.

虽然我不会特别建议在实践中这样做,但是如果是用于调试目的,那就可以了。您可以将其作为NSObject上的一个类别来实现,并在调试时将其保存起来以供使用。如果完成了所有类型的编码,那么它将成为一个非常好的小方法。

#3


0  

yes, one way would be to ask for all properties and then use KVC for example:

是的,一种方法是要求所有的属性,然后使用KVC例如:

//properties
unsigned int cProperties = 0;
objc_property_t *props = class_copyPropertyList(self.class, &cProperties);
for(int i = 0; i < cProperties; i++) {
    const char *name = property_getName(props[i]);
    NSLog(@"%@=%@", name, [self valueForKey:name];
}

an alternate way is to go through all the methods of a class, get the return type, invoke and print it

另一种方法是遍历类的所有方法,获取返回类型,调用并打印它。

#4


-3  

The quick and dirty would be to override debugDescription:

快速而肮脏的是重写debugDescription:

-(NSString*)debugDescription {
    NSString *str = [[NSString alloc] initWithFormat:@"My BOOL 1: %d, My Float: %f", self.myBool, self.myFoat];
    return str;
}

Of course, if your object is complex, this could be time consuming.

当然,如果你的对象是复杂的,这可能会很耗时。

#1


24  

This question seems the have the answer to your question.

这个问题似乎是你问题的答案。

Update:

I got curious and made a catagory:

我很好奇,于是做了个问答:

//Using Xcode 4.5.2 - iOS 6 - LLDB - Automatic Reference Counting

//NSObject+logProperties.h    
@interface NSObject (logProperties)
- (void) logProperties;
@end

//NSObject+logProperties.m
#import "NSObject+logProperties.h"
#import <objc/runtime.h>

@implementation NSObject (logProperties)

- (void) logProperties {

    NSLog(@"----------------------------------------------- Properties for object %@", self);

    @autoreleasepool {
        unsigned int numberOfProperties = 0;
        objc_property_t *propertyArray = class_copyPropertyList([self class], &numberOfProperties);
        for (NSUInteger i = 0; i < numberOfProperties; i++) {
            objc_property_t property = propertyArray[i];
            NSString *name = [[NSString alloc] initWithUTF8String:property_getName(property)];
            NSLog(@"Property %@ Value: %@", name, [self valueForKey:name]);
        }
        free(propertyArray);
    }    
    NSLog(@"-----------------------------------------------");
}

@end

Include it in your class: #import "NSObject+logProperties.h"

在你的类中包含它:#import "NSObject+logProperties.h"

and call [self logProperties]; to those properties!

并调用(自我logProperties);这些属性!

#2


5  

The current answers just show how to do it for properties. If you want every instance variable printed out you could do something like the below.

当前的答案只是显示如何对属性进行处理。如果您想打印出每个实例变量,您可以做如下操作。

- (void)logAllProperties {
    unsigned int count;
    Ivar *ivars = class_copyIvarList([self class], &count);
    for (unsigned int i = 0; i < count; i++) {
        Ivar ivar = ivars[i];

        const char *name = ivar_getName(ivar);
        const char *type = ivar_getTypeEncoding(ivar);
        ptrdiff_t offset = ivar_getOffset(ivar);

        if (strncmp(type, "i", 1) == 0) {
            int intValue = *(int*)((uintptr_t)self + offset);
            NSLog(@"%s = %i", name, intValue);
        } else if (strncmp(type, "f", 1) == 0) {
            float floatValue = *(float*)((uintptr_t)self + offset);
            NSLog(@"%s = %f", name, floatValue);
        } else if (strncmp(type, "@", 1) == 0) {
            id value = object_getIvar(self, ivar);
            NSLog(@"%s = %@", name, value);
        }
        // And the rest for other type encodings
    }
    free(ivars);
}

Although I wouldn't particularly suggest doing this in practice, but if it's for debug purposes then that's fine. You could implement this as a category on NSObject and keep it lying around for use when debugging. If completed for all type encodings then it could make for a very nice little method.

虽然我不会特别建议在实践中这样做,但是如果是用于调试目的,那就可以了。您可以将其作为NSObject上的一个类别来实现,并在调试时将其保存起来以供使用。如果完成了所有类型的编码,那么它将成为一个非常好的小方法。

#3


0  

yes, one way would be to ask for all properties and then use KVC for example:

是的,一种方法是要求所有的属性,然后使用KVC例如:

//properties
unsigned int cProperties = 0;
objc_property_t *props = class_copyPropertyList(self.class, &cProperties);
for(int i = 0; i < cProperties; i++) {
    const char *name = property_getName(props[i]);
    NSLog(@"%@=%@", name, [self valueForKey:name];
}

an alternate way is to go through all the methods of a class, get the return type, invoke and print it

另一种方法是遍历类的所有方法,获取返回类型,调用并打印它。

#4


-3  

The quick and dirty would be to override debugDescription:

快速而肮脏的是重写debugDescription:

-(NSString*)debugDescription {
    NSString *str = [[NSString alloc] initWithFormat:@"My BOOL 1: %d, My Float: %f", self.myBool, self.myFoat];
    return str;
}

Of course, if your object is complex, this could be time consuming.

当然,如果你的对象是复杂的,这可能会很耗时。