12

オブジェクトのパブリック プロパティを検査し、encodeWithCoder: および initWithCoder: の汎用実装を生成することにより、汎用 NSCoding 実装を記述できるようにする、Objective-C のリフレクションの手段はありますか。

リフレクションを使用してJavaオブジェクトをシリアル化および逆シリアル化する一般的な方法を可能にするXStream for Javaのようなものを考えています。さらに良いのは、プロパティをシリアライズしたいもの、または一時的なものとしてマークする手段です (Java の一時的なキーワードのように)。

Archives and Serializations Programming Guide for Cocoaのドキュメントを読んでいます。オブジェクトのシリアル化をある程度制御したいということは理解していますが、それは一般的に対称的なプロセスであり、シリアル化のためにコード化されているものを逆シリアル化する必要があるのは奇妙に思えます。私は DRY の信奉者です (同じことを繰り返さないでください)。

4

4 に答える 4

12

それが可能であるだけでなく、まさにそれを行うことに挑戦した友人がいます. (彼のブログについては、こちらを参照してください。) リフレクションは、 Objective-C 2.0 Runtime Referenceに記載されている Objective-C ランタイム関数を使用して行われます。見てください。

ただし、これは、すべてのインスタンス変数を保存するという一般的な動作が必要な場合にのみ機能することに注意してください。ただし、NSView でそのスーパービューを保存したくない場合があります。そのような場合、一般的なケースは機能しません。

保存したいインスタンス変数のプロパティを宣言し、他の変数を「非表示」のままにすることで、シリアル化するものとシリアル化しないものを区別できると考えられますが、それはプロパティの目的全体をわずかな利益にねじ曲げています. 私はそれをお勧めしません。

于 2009-05-28T05:20:29.113 に答える
6

(私はBJ Homerのコメントにリンクされているブログ投稿の著者です)。コードを使用する際の注意点がいくつかあります。

  1. ターゲットクラスはKVCに準拠している必要があります。ivarにObjective-C2.0プロパティを使用している場合は、これですべて設定できます。それ以外の場合は、valueForKey:メソッドとsetValue:forKey:メソッドに適切に応答するようにクラスが設定されていることを確認する必要があります。
  2. このコードは、ランタイムの文書化されていない「機能」を使用して、ivarクラスをNSCodingに再帰的に適合させます。コンパイルすると、ほとんどすべての入力情報(AFAIK)がコードから削除されますが、ivarを保存するには、NSCodingに準拠する必要があります。ivarがオブジェクトであり、その上でivar_getTypeEncoding()を呼び出すと、{#IVAR_CLASS}(例:{#NSString})のようなAC文字列が返されることを発見しました。私がやっていることは、#と}の間の文字列を取得し、NSClassFromStringを使用してClassオブジェクトを作成し、それを繰り返します。
  3. このコードはすべてのivarを保存します。
  4. ご自身の責任で使用してください(もちろん)

私はこれを主に概念実証として作成しましたが、このコードが見事に失敗する場合が多くあります。たとえば、オブジェクトAにBのivarがあり、BにAのivarがある場合、コードを使用していずれかをシリアル化すると、(私は)無限ループが発生します。

それでも、Objective-Cを使用すると、そもそも同じようなことができるのは、かなり驚異的だと思います。

于 2009-06-02T02:11:44.013 に答える
0

RMModelObject をチェックしてください:

http://www.realmacforge.com/svn/trunk/RMModelObject/

ただし、ObjC ランタイムは 10.5 とシミュレータでは機能しますが、実際の iPhone では機能しないことに注意してください。難しい方法でそれを見つけました..おそらくOS 3.0が最終的にそれをサポートしますが、私は確認していません.

于 2009-07-02T23:18:36.603 に答える
0

まさにこの目的のために今夜これを書きました。#import を忘れないでください!これは、クラス内のすべての @properties が NSObject フォームであることを前提としているため、float ではなく NSNumber などです。

#import <objc/runtime.h>

-(id)initWithCoder:(NSCoder *)decoder {
    if (self = [super init]) {
        uint count;
        objc_property_t *properties = class_copyPropertyList(self.class, &count);
        for (int i = 0; i < count ; i++) {
            const char* propertyName = property_getName(properties[i]);
            NSString *key = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
            NSValue *value = [decoder decodeObjectForKey:key];
            [self setValue:value forKey:key];
        }
        free(properties);
    }
    return self;
}

- (void)encodeWithCoder:(NSCoder *)encoder {
    uint count;
    objc_property_t *properties = class_copyPropertyList(self.class, &count);
    for (int i = 0; i < count ; i++) {
        const char* propertyName = property_getName(properties[i]);
        NSString *key = [NSString stringWithCString:propertyName encoding:NSUTF8StringEncoding];
        NSValue *value = [self valueForKey:key];
        [encoder encodeObject:value forKey:key];
    }
    free(properties);
}
于 2018-10-10T07:41:41.017 に答える