直接干净地访问这些实例变量的唯一方法是通过提供有用功能的 Objective-C 运行时object_getInstanceVariable。该值通过引用传回,并且可以是许多不同的类型,因此在调试器中它不是很有用。但是你的问题启发了我想出一个解决方案。
我在 NSObject 上编写了一个类别,允许您从调试器内省实例变量,而不必担心访问器的副作用。将类别添加到项目后,您可以执行以下操作:
(lldb) po [self valueOfInstanceVariable:@"_name"]
IMG_4078.PNG
这是代码:
NSObject+IvarIntrospection.h
#if DEBUG
#import <Foundation/Foundation.h>
@interface NSObject (IvarIntrospection)
- (id)valueOfInstanceVariable:(NSString *)ivarName;
@end
#endif
NSObject+IvarIntrospection.m
#if DEBUG
#import "NSObject+IvarIntrospection.h"
#import <objc/runtime.h>
@implementation NSObject (IvarIntrospection)
- (id)valueOfInstanceVariable:(NSString *)ivarName {
    // Get the value of the instance variable
    // Use a union in order to convert the value to a float or double (see http://en.wikipedia.org/wiki/Type_punning)
    union {
        void *value;
        float f;
        double d;
    } ivar;
    Ivar ivarInfo = object_getInstanceVariable(self, [ivarName UTF8String], &ivar.value);
    // If the instance variable doesn't exist, try adding an underscore
    if (!ivarInfo && ![ivarName hasPrefix:@"_"]) {
        NSString *underscoredIvarName = [@"_" stringByAppendingString:ivarName];
        NSLog(@"Instance variable '%@' does not exist. Perhaps you meant '%@?' Let's try that.", ivarName, underscoredIvarName);
        return [self valueOfInstanceVariable:underscoredIvarName];
    // If there's already an underscore, error
    } else if (!ivarInfo) {
        NSLog(@"Instance variable '%@' does not exist.", ivarName);
        return nil;
    }
    // Figure out what type the instance variable is and return a sensible representation
    const char *type = ivar_getTypeEncoding(ivarInfo);
    switch (type[0]) {
        case 'c':
            return [NSNumber numberWithChar:(char)ivar.value];
        case 'i':
            return [NSNumber numberWithInt:(int)ivar.value];
        case 's':
            return [NSNumber numberWithShort:(short)ivar.value];
        case 'l':
            return [NSNumber numberWithLong:(long)ivar.value];
        case 'q':
            return [NSNumber numberWithLongLong:(long long)ivar.value];
        case 'C':
            return [NSNumber numberWithUnsignedChar:(unsigned char)ivar.value];
        case 'I':
            return [NSNumber numberWithUnsignedInt:(unsigned int)ivar.value];
        case 'S':
            return [NSNumber numberWithUnsignedShort:(unsigned short)ivar.value];
        case 'L':
            return [NSNumber numberWithUnsignedLong:(unsigned long)ivar.value];
        case 'Q':
            return [NSNumber numberWithUnsignedLongLong:(unsigned long long)ivar.value];
        case 'f':
            return [NSNumber numberWithFloat:ivar.f];
        case 'd':
            return [NSNumber numberWithDouble:ivar.d];
        case '*':
            return [NSString stringWithUTF8String:(const char *)ivar.value];
        case '@':
        case '#':
            return (id)ivar.value;
        case ':':
            return NSStringFromSelector((SEL)ivar.value);
        default:
            return [NSValue valueWithBytes:&ivar.value objCType:type];
    }
}
@end
#endif
请注意,编译发布时该类别将被自动禁用(感谢调试宏)。