【问题标题】:UIView as dictionary key?UIView 作为字典键?
【发布时间】:2010-06-07 19:04:13
【问题描述】:

我想要一个从UIViews 映射到其他东西的NSDictionary

但是,由于 UIViews 没有实现NSCopying 协议,我不能直接将它们用作字典键。

【问题讨论】:

  • 这听起来是个非常糟糕的主意。
  • 仅当您不知道数据可能会变成垃圾的事实时(正如公认的答案所指出的那样)。
  • @Yar 可能是关联对象?
  • 你也可以使用CFDictionaryNSHashMap

标签: iphone objective-c uiview nsdictionary nscopying


【解决方案1】:

您可以使用NSValue 持有指向UIView 的指针并将其用作键。 NSValues 是可复制的。但是,如果视图被破坏,NSValue 将持有 垃圾指针。

【讨论】:

  • 太棒了!我正要使用带有 UIView 哈希的 NSNumber 作为 int。我认为这要好得多。
  • 现在使用 ARC 你必须使用valueWithNonretainedObject
  • @Yar 以下是使用 luvieere 和您自己的建议的实际代码:stackoverflow.com/a/11387017/974531
【解决方案2】:

这是实际代码(基于 the answer by luvieere 和 Yar 的进一步建议):

// create dictionary
NSMutableDictionary* dict = [NSMutableDictionary new];
// set value
UIView* view = [UILabel new];
dict[[NSValue valueWithNonretainedObject:view]] = @"foo";
// get value
NSString* foo = dict[[NSValue valueWithNonretainedObject:view]];

【讨论】:

  • 如何检查视图是否被释放?
【解决方案3】:

虽然这并不是它们真正的用途,但您可以使用Associative References 来创建一个类似于字典的功能界面:

static char associate_key;
void setValueForUIView(UIView * view, id val){
    objc_setAssociatedObject(view, &associate_key, val, OBJC_ASSOCIATION_RETAIN);
}

id valueForUIView(UIView * view){
    return objc_getAssociatedObject(view, &associate_key);
}

您甚至可以将其封装在一个类中 ThingWhatActsLikeADictionaryButWithKeysThatArentCopyable*;在这种情况下,您可能希望保留用作键的视图。

类似这样的东西(未经测试):

#import "ThingWhatActsLikeADictionaryButWithKeysThatArentCopyable.h"
#import <objc/runtime.h>

static char associate_key;

@implementation ThingWhatActsLikeADictionaryButWithKeysThatArentCopyable

- (void)setObject: (id)obj forKey: (id)key
{
    // Remove association and release key if obj is nil but something was
    // previously set
    if( !obj ){
        if( [self objectForKey:key] ){
            objc_setAssociatedObject(key, &associate_key, nil, OBJC_ASSOCIATION_RETAIN);
            [key release];

        }
        return;
    }

    [key retain];
    // retain/release for obj is handled by associated objects functions
    objc_setAssociatedObject(key, &associate_key, obj, OBJC_ASSOCIATION_RETAIN);
}

- (id)objectForKey: (id)key 
{
    return objc_getAssociatedObject(key, &associate_key);
}

@end

*名称可能需要修改。

【讨论】:

    【解决方案4】:

    如果您在 iOS 6 之前不需要支持,NSMapTable(由neilsbot 建议)运行良好,因为它可以为集合中的键提供枚举器。这对于所有文本字段共有的代码很方便,例如设置委托或将文本值与 NSUserDefaults 实例双向同步。

    在 viewDidLoad 中

    self.userDefFromTextField = [NSMapTable weakToStrongObjectsMapTable];
    [self.userDefFromTextField setObject:@"fooUserDefKey" forKey:self.textFieldFoo];
    [self.userDefFromTextField setObject:@"barUserDefKey" forKey:self.textFieldBar];
    // skipped for clarity: more text fields
    
    NSEnumerator *textFieldEnumerator = [self.userDefFromTextField keyEnumerator];
    UITextField *textField;
    while (textField = [textFieldEnumerator nextObject]) {
        textField.delegate = self;
    }
    

    在视图中将出现:

    NSEnumerator *keyEnumerator = [self.userDefFromTextField keyEnumerator];
    UITextField *textField;
    while (textField = [keyEnumerator nextObject]) {
        textField.text = [self.userDefaults stringForKey:[self.textFields objectForKey:textField]];
    }
    

    在 textField:shouldChangeCharactersInRange:replacementString:

    NSString *resultingText = [textField.text stringByReplacingCharactersInRange:range withString:string];
    if(resultingText.length == 0) return YES;
    
    NSString *preferenceKey = [self.textFields objectForKey:textField];
    if(preferenceKey) [self.userDefaults setString:resultingText forKey:preferenceKey];
    return YES;
    

    现在我要哭了,因为我在意识到我的 iOS 5.1 目标应用程序无法使用它之前实现了所有这些。 NSMapTable 是在 iOS 6 中引入的。

    【讨论】:

    • 这是一个很好的解决方案!
    【解决方案5】:

    与其存储指向视图的指针并冒着垃圾问题的风险,不如给 UIView 一个标签并将标签的值存储在字典中。更安全。

    【讨论】:

      【解决方案6】:

      我使用的是Objective-C++提供的ARC下的简单解决方案。

      MyClass.mm:

      #import <map>
      
      @implementation MyClass
      {
          std::map<UIView* __weak, UIColor* __strong> viewMap;
      }
      
      - (void) someMethod
      {
          viewMap[self.someView] = [UIColor redColor];
      }
      

      在这个例子中,我通过使所有值都必须是 UIColor* 来获得更强大的类型检查,这正是我所需要的。但是如果你想允许任何对象作为值,你也可以使用id 作为值类型,例如:std::map&lt;UIView* __weak, id __strong&gt; viewMap; 同样对于键:id __weak, id __strong&gt; viewMap;

      您还可以根据需要更改__strong__weak 属性。在我的例子中,视图已经被我使用它的视图控制器保留了,所以我认为不需要指向它们的强指针。

      【讨论】:

      • NSMapTable 也提供了这个。参考文献[NSMapTable weakToStrongObjectsMapTable]
      【解决方案7】:

      当你偶尔需要UIView作为键时,一个简单的解决方案,我用它来存储UILabelUIColor

      NSArray<UIView *> *views = @[viewA,viewB,viewC,viewD];
      NSArray *values = @[valueA,valueB,valueC,valueD];
      
      for(int i = 0;i < 4;i++) {
          UIView *key = views[i];
          id value = values[i]
          //do something
      }
      
      id value = values[[views indexOfObject:key]]
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-02-07
        • 2011-09-20
        • 2014-07-06
        • 2012-04-18
        • 2013-07-25
        • 1970-01-01
        相关资源
        最近更新 更多