27

我想要一个NSDictionaryUIViews 映射到其他东西的东西。

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

4

7 回答 7

30

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

于 2010-06-07T19:09:20.710 回答
17

这是实际代码(基于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]];
于 2012-07-08T21:53:32.193 回答
4

尽管这并不是它们真正的用途,但您可以使用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

*名称可能需要一些工作。

于 2012-07-08T22:04:13.327 回答
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 中引入的。

于 2014-12-09T22:06:50.380 回答
1

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

于 2012-10-18T23:48:50.350 回答
0

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

我的班级.mm:

#import <map>

@implementation MyClass
{
    std::map<UIView* __weak, UIColor* __strong> viewMap;
}

- (void) someMethod
{
    viewMap[self.someView] = [UIColor redColor];
}

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

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

于 2014-03-04T00:42:24.303 回答
0

一个简单的解决方案,当你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]]
于 2017-07-21T08:45:31.293 回答