4

iOSアプリケーションに次のクラスがあります(Javaの世界の抽象クラスのようなものです)。

@implementation WSObject

static NSDictionary* _dictionary = nil;
+(NSDictionary*) dictionary {
    if (_dictionary == nil) {
        _dictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]];
    }
    return _dictionary;
}

...

@end

WSObject次に、クラスメソッドを使用して上記を実装する複数のクラスがありますdictionary。問題は、これらのクラスのそれぞれに独自の_dictionaryが必要ですが、それらはすべてスーパークラスの同じオブジェクトを共有しているということです。もちろん、すべてのサブクラスにコピーすることはできますが、それでは再利用性が損なわれます。このゲッターの他にWSObject、辞書を変更する他のクラスメソッドがあります。このため、すべてのサブクラスに存在する必要があるいくつかのクラスメソッドがあります。

どうすればこれを賢く解決できますか?説明が不十分な場合は教えてください。

4

3 に答える 3

9

連想参照は、うまくいくようです。基本的に、クラスオブジェクト自体にストレージを追加することができます。(NSStringここでは、デモンストレーションのために、使用する辞書の代わりにsを使用しています。)

スーパークラス:

#import <Foundation/Foundation.h>
#import <objc/runtime.h>

@interface Stuper : NSObject

// Accessor method for the "class variable"
+ (NSString *) str;
// Analog to your +localStorePath
+ (NSString *) quote;

@end

#import "Stuper.h"

// The doc suggests simply using the address of a static variable as the key.
// This works fine, even though every class is (as in your problem) using
// the same key, because we are associating to a different class each time.
static char key;    
@implementation Stuper

+ (NSString *) str {
    NSString * s = objc_getAssociatedObject(self, &key);
    if( !s ){
        s = [self quote];
        // You'll probably want to use OBJC_ASSOCIATION_RETAIN for your dictionary.
        // self inside a class method is the class object; use that as
        // the associator. The string is now tied to the associator, i.e.,
        // has the same lifetime.
        objc_setAssociatedObject(self, &key, s, OBJC_ASSOCIATION_COPY);
    }
    return s;
}

+ (NSString *) quote {
    return @"It was the best of times, it was the worst of times.";
}

@end



サブクラス:

#import "Stuper.h"
@interface Stub : Stuper @end

#import "Stub.h"

@implementation Stub

+ (NSString *) quote {
    return @"Call me Ishmael.";
}

@end



これを試してみてください:

#import <Foundation/Foundation.h>
#import "Stuper.h"
#import "Stub.h"

int main (int argc, const char * argv[])
{

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];

    NSLog(@"%@", [Stuper str]);
    NSLog(@"%@", [Stub str]);

    [pool drain];
    return 0;
}

各クラスオブジェクトには、独自の文字列が関連付けられています。

2011-12-05 23:11:09.031 SubClassVariables [36254:903]最高の時であり、最悪の時でした。
2011-12-05 23:11:09.034 SubClassVariables [36254:903]私をイシュメールと呼んでください。

ここでの唯一の欠点は、オブジェクトが必要になるたびにアクセサメソッドを呼び出さなければならないことです。直接使用できるポインタがありません。objc_getAssociatedObjectもちろん、にアクセスできるので、アクセサーとしてスーパークラスを呼び出すこともできますkey

于 2011-12-05T23:18:04.067 に答える
7

各サブクラスに独自のディクショナリを与えるには、クラス名をキーとして使用して、プライマリディクショナリに2番目のディクショナリオブジェクトを格納します。例えば:

static NSMutableDictionary *_dictionary = nil;

+ (NSDictionary*)dictionary 
{
    if (_dictionary == nil) 
        _dictionary = [[NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]] mutableCopy];

    NSString *key = NSStringFromClass( [self class] );

    if ( [_dictionary objectForKey:key] == nil )
        [_dictionary setObject:[NSMutableDictionary dictionary] forKey:key];

    return [_dictionary objectForKey:key];
}
于 2011-12-05T22:28:30.457 に答える
2

おそらくあなたは辞書のコピーを返すことができます

@implementation WSObject

static NSDictionary* _dictionary = nil;
+(NSDictionary*) dictionary {
    if (_dictionary == nil) {
        _dictionary = [NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]];
    }
    return [_dictionary copy];
}

...

@end

変更_dictionaryすると、変更された辞書のコピーが取得されることに注意してください。これは、ディスク上にあるものとは異なる場合があります。

これはどのくらいの頻度で呼び出されますか?_dictionaryこの静的オブジェクトにファイルの内容をキャッシュする必要が本当にありますか?

パフォーマンスが問題になることはあまりないので、ディスクから毎回フェッチしてみませんか。

@implementation WSObject

+(NSDictionary*) dictionary {
    return [NSKeyedUnarchiver unarchiveObjectWithFile:[self localStorePath]];
}

...

@end
于 2011-12-05T22:24:38.543 に答える