【问题标题】:How should I construct an NSDictionary with multiple keys?我应该如何构造具有多个键的 NSDictionary?
【发布时间】:2010-12-08 05:08:23
【问题描述】:

我有一种情况,我想将一对对象映射到信息字典。我想避免创建 NSDictionary 的 NSDictionary 的 NSDictionary,因为这简直令人困惑且难以维护。

例如,如果我有两个类,Foo 和 Bar,我想要 {Foo, Bar} -> {NSDictionary}

除了基于所讨论的两种类型创建自定义类(仅用作字典键)之外,还有其他选择吗?也许类似于 STL 的 pair 类型,我只是不知道?

【问题讨论】:

    标签: objective-c cocoa nsdictionary


    【解决方案1】:

    就像你说的,你可以创建一个 Pair 类:

    //Pair.h
    @interface Pair : NSOpject <NSCopying> {
      id<NSCopying> left;
      id<NSCopying> right;
    }
    @property (nonatomic, readonly) id<NSCopying> left;
    @property (nonatomic, readonly) id<NSCopying> right;
    + (id) pairWithLeft:(id<NSCopying>)l right:(id<NSCopying>)r;
    - (id) initWithLeft:(id<NSCopying>)l right:(id<NSCopying>)r;
    @end
    
    //Pair.m
    #import "Pair.h"
    @implementation Pair
    @synthesize left, right;
    
    + (id) pairWithLeft:(id<NSCopying>)l right:(id<NSCopying>)r {
     return [[[[self class] alloc] initWithLeft:l right:r] autorelease];
    }
    
    - (id) initWithLeft:(id<NSCopying>)l right:(id<NSCopying>)r {
      if (self = [super init]) {
        left = [l copy];
        right = [r copy];
      }
      return self;
    }
    
    - (void) finalize {
      [left release], left = nil;
      [right release], right = nil;
      [super finalize];
    }
    
    - (void) dealloc {
      [left release], left = nil;
      [right release], right = nil;
      [super dealloc];
    }
    
    - (id) copyWithZone:(NSZone *)zone {
      Pair * copy = [[[self class] alloc] initWithLeft:[self left] right:[self right]];
      return copy;
    }
    
    - (BOOL) isEqual:(id)other {
      if ([other isKindOfClass:[Pair class]] == NO) { return NO; }
      return ([[self left] isEqual:[other left]] && [[self right] isEqual:[other right]]);
    }
    
    - (NSUInteger) hash {
      //perhaps not "hashish" enough, but probably good enough
      return [[self left] hash] + [[self right] hash];
    }
    
    @end
    

    编辑:

    关于创建可以作为键的对象的一些注意事项:

    1. 它们必须符合NSCopying 协议,因为我们不希望密钥从我们下面掉出来。
    2. 由于 Pair 本身已被复制,我确保 Pair 中的对象也被复制。
    3. 密钥必须实现isEqual:。我实现了hash 方法,但它可能没有必要。

    【讨论】:

    • 戴夫,2 个问题。 1) 我想在 copyWithZone 中分配 allocWithZone,对吗? 2) 使用 id 代替 NSObject* 有什么好处吗?
    • 如果你实现 isEqual: 你绝对必须实现 -hash。不变式是如果 [a isEqual:b],则 [a hash] 必须 == [b hash]。
    • @nall(对不起,错过了您的评论) 1:+alloc 是通过调用+allocWithZone: 实现的,所以它可能不会有什么不同。 2:没有真正的好处。我更喜欢id&lt;NSCopying&gt;,因为它 a) 输入更少,b) 初始化程序返回 id,而不是 NSObject *(或类似变体)。诚然,您将很少拥有一个不返回某些NSObject 子类的初始化程序,但这并非不可能。 NSObject 不是唯一的根类。
    • 你可以删掉那个finalize方法。 release 是 GC 中的空操作,您不需要 finalize 方法来将 ivars 设置为 nil;在 GC 获取您的对象后,这些引用无论如何都会消失。
    【解决方案2】:

    您可以尝试NSMapTable,然后您的密钥几乎可以是任何东西,如果您愿意,也可以是指向结构的指针。

    (以下 cmets 的附录:NSMapTable 曾经不在 iOS 上,但从 iOS 6 开始可用。)

    【讨论】:

    • 这是一个很好的提示,但是 NSMapTable 在 iOS(当前为 5.0.1)中不可用。
    • 这是有道理的,因为 NSMapTable 主要是作为 Objective-C 垃圾收集的辅助开发的(尽管它在非 GC 环境中非常有用)。如果你想要一些行为类似于 NS(Mutable)Dictionary 但支持非对象类型的东西,那么总会有 CFMutableDictionary。
    • 关于 NSMapTable 的更多信息:stackoverflow.com/questions/6904533/…
    【解决方案3】:

    正在使用某种效果

    [NSString stringWithFormat:@"%@ %@", [obj1 key_as_string], [oj2 key_as_string]]

    对你没有好处,key_as_string 是你的对象类的一部分吗?即从字符串中创建一个键。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 2014-10-22
      • 1970-01-01
      相关资源
      最近更新 更多