1

自分のオブジェクトのコレクションをNSDictionary(JSON用)に深く解析しようとしています。

すべてのモデルが拡張する基本オブジェクトクラスがあり、この基本オブジェクトはNSObjectを拡張します。

@interface BaseObj : NSObject <DICTMaker>
    - (NSMutableDictionary *) toDICT;
@end

このメソッドでは、objc-runtimeを使用してプロパティのリストを取得します。を使用して参照を取得できるプロパティはすべて[self valueForKey:]、先に進んで、プロパティの名前と値を辞書に挿入します。

ただし、これまでに気付いたのは、NSNumbersとユーザー定義のクラスが辞書に追加されていないことです。私のパーサーは、すべてをログに吐き出しているので、最も確実にそれらを識別します。ただし、すべてのユーザー定義オブジェクトを[self valueForKey:]返します。nilNSNumbers

- (NSMutableDictionary *)toDICT {
    NSMutableDictionary *props = [NSMutableDictionary dictionary];
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    for (i = 0; i < outCount; i++) {
        objc_property_t property = properties[i];

        // Both of these work, I promise:
        NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];
        NSString *propertyType = [NSString stringWithUTF8String:getPropertyType(property)];

        NSLog( @"%@ of Type: %@", propertyName, propertyType );
        id propertyValue = [self valueForKey:propertyName];
        if ( [ propertyValue respondsToSelector:@selector(toDICT:) ] )
            [ props setObject:[propertyValue toDICT] forKey:propertyName ];
        else if ( propertyValue )
            [ props setObject:propertyValue forKey:propertyName ];
        else
            NSLog( @"Unable to get ref to: %@", propertyName );
    }
    free(properties);
    return props;
}

これが私が作成者に投げたサンプルオブジェクトです:

@interface UserRegistrationLocation : BaseObj {
    NSString *address, *street, *street_2, *city;
    NSNumber *addr_state, *addr_zip;
}

@interface UserRegistrationContact : BaseObj {
    NSString *first_name, *last_name;
    NSString *p_phone_area, *p_phone_first_3, *p_phone_last_4;
    NSString *s_phone_area, *s_phone_first_3, *s_phone_last_4;
}

@interface UserRegistration : BaseObj {
    NSString *email, *password, *password_confirm;
    NSNumber *referral;

    UserRegistrationContact *primary, *secondary;
    UserRegistrationLocation *address;
}

NSMutableDictionary *mydict = [myUserRegistration toDICT];

結果の辞書には、email、password、およびpassword_confirmのエントリのみが含まれていました。

[11012:f803] Unable to get ref to: referral
[11012:f803] Unable to get ref to: primary
[11012:f803] Unable to get ref to: secondary
[11012:f803] Unable to get ref to: address
[11012:f803] {"user":{"password":"haxme123","password_confirm":"haxme123","email":"my@email.com"}}

助けてください=}!

4

2 に答える 2

2

プロパティではなく、値に対してivarを宣言しただけです。宣言class_copyPropertyListが必要です。@propertyなどのivarアクセス​​関数を使用できますclass_getInstanceVariable

ただし、このアプローチは少し賢くなりすぎていると思います。シリアル化するキーの配列を返すメソッドを実装します。たとえば、-(NSArray *)keysForJSONSerialization。これにより、意図がより明確になり、特定のプロパティのシリアル化を防ぐことができます(ある時点で必要になると思います)。

于 2012-06-11T14:41:41.413 に答える
1

たぶん私は問題を間違って理解しましたが、あなたの紹介は主要であり、単にヌルではありませんか?それらがkeyvalueストアにない場合は、例外が発生します。それ以外の部分は、プロパティがkeyvalueストアにあるが、nilが割り当てられている場合にのみ呼び出されます。少なくともサンプルコードからは、値が設定されているかどうかを判断することはできません。

あなたの例を以下のコードに還元すると、次の値の出力テストが得られます:(null)参照を取得できません:test aNumber with Value:5

testはnullであり、メッセージに「unable...」が表示されます。aNumberは正しいです。テストをテキストに変更すると、「unable...」の部分が消えます。copyPropertyListはプロパティのみをコピーするため、プロパティではない追加のメンバー変数_noPropはここでは発生しません。

@interface TestValueForKey : NSObject {
     NSString* _test;
     NSString* _noProp;
     NSNumber* _aNumber;
}

@property (retain) NSString* test;
@property (retain) NSNumber* aNumber;

-(void)myTest;

@implementation TestValueForKey

@synthesize test = _test;
@synthesize aNumber = _aNumber;

-(id)init
{
    if( (self = [super init]) != nil) {
       _test = nil;
       _aNumber = [NSNumber numberWithInt:5];
    }

    return self;
}

-(void)myTest
{
    NSMutableDictionary *props = [NSMutableDictionary dictionary];
    unsigned int outCount, i;
    objc_property_t *properties = class_copyPropertyList([self class], &outCount);
    for( i = 0; i < outCount; i++) {
       objc_property_t property = properties[i];

       // Both of these work, I promise:
       NSString *propertyName = [NSString stringWithUTF8String:property_getName(property)];

      id propertyValue = [self valueForKey:propertyName];
      NSLog( @"%@ with Value: %@", propertyName, propertyValue );
      if ( propertyValue )
          [ props setObject:propertyValue forKey:propertyName ];
      else
          NSLog( @"Unable to get ref to: %@", propertyName );
  }
  free(properties);
}
@end
于 2012-06-11T19:27:28.637 に答える