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,但它们都共享来自超类的相同对象。当然,我可以复制到所有子类,但这会破坏可重用性。除了这个 getter,还有其他类方法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] 叫我 Ishmael。

唯一的缺点是每次需要对象时都必须调用访问器方法。您没有可以直接使用的指针。objc_getAssociatedObject当然,您也可以将超类作为访问器调用,因为它可以访问key.

于 2011-12-05T23:18:04.067 回答
7

为了给每个子类自己的字典,使用类名作为键在主字典中存储第二个字典对象。例如:

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 回答