7

MyClass.h :

@interface MyClass : NSObject
@end

MyClass.m :

// Define a private variable in a class extension
@interface MyClass () {
    NSString *name;
}
@end

その後、lldb で次のようにします。

(lldb) po myClassInstance->name
error: 'MyClass' does not have a member named 'name'
error: 1 errors parsing expression

では、デバッガーでその変数にどのようにアクセスするのでしょうか?

xcode 4.3.2 の使用

ありがとう!

4

3 に答える 3

6

(lldb) po [myClassInstance valueForKey:@"name"]

于 2012-04-26T03:03:28.310 に答える
0

これらのインスタンス変数にクリーンに直接アクセスする唯一の方法は、便利な関数を提供する 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

リリース用にコンパイルすると、カテゴリは自動的に無効になることに注意してください (デバッグ マクロのおかげです)。

于 2014-05-09T06:05:10.400 に答える
-3

nameメソッドの外からアクセスする必要がある場合はMyClass、それにアクセスするためのメソッドを定義する必要があります。(NSString*) nameとというメソッドを書くこともできますが- (void) setName:(NSString*) newName、プロパティを定義して合成する方が簡単です。

MyClass.hで、プロパティを定義します。文字列の場合、通常は次のようにしますcopy

@interface MyClass : NSObject

@property (copy) NSString* name;

@end

MyClass.mでは、引き続き ivar を使用してインターフェイス宣言を使用します。

@interface MyClass () {
    NSString *name;
}
@end

ただし、新しいプロパティを合成する必要もあります。これにより、 nameを取得および設定するためのメソッドが作成されます。

@implementation MyClass

@synthesize name = name;

@end

慣例として、ivar の先頭または末尾にアンダースコアを付けるのが一般的です。そのため、インターフェースNSString *_name;では 、実装では@synthesize name = _name. これにより、プロパティを意味するときに誤って ivar を使用するのを防ぐことができます。

nameプロパティにアクセスできるようになりました。

MyClass me = [[[MyClass alloc] init] autorelease];
[me setName:@"My name"];
NSLog(@"Name = %@", [me name]);

Objective-C のプロパティは言語の強力な機能ですが、習得しなければならない癖がいくつかあります。"objective-C"、"properties"、"synthesize" の組み合わせを Web 検索してみてください。

それでもコンパイル エラーが発生する場合は、アクセスするコードの部分で質問を編集してくださいname

于 2012-04-26T02:57:09.003 に答える