我希望有NSDictionary
从UIView
映射到其他内容。
但是,由于UIViews没有实现NSCopying
协议,我不能直接将它们用作字典键。
答案 0 :(得分:30)
您可以使用NSValue
按住指针UIView
并将其用作关键字。 NSValues
是可复制的。但是,如果视图被销毁,NSValue
将保持一个
垃圾指针。
答案 1 :(得分:17)
以下是实际代码(基于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]];
答案 2 :(得分: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
*这个名字可能需要一些工作。
答案 3 :(得分: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;
}
在viewWillAppear中:
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中引入的。
答案 4 :(得分:1)
不是存储指向视图的指针并冒着垃圾问题的风险,只需给UIView一个标记并将标记的值存储在字典中。更安全。
答案 5 :(得分:0)
我在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<UIView* __weak, id __strong> viewMap;
同样适用于键:id __weak, id __strong> viewMap;
您还可以根据需要更改__strong
和__weak
属性。在我的例子中,视图已经由我使用它的视图控制器保留,所以我看到没有必要强烈指向它们。
答案 6 :(得分:0)
一个简单的解决方案,当你偶尔想要UIView
作为关键时,我用它来存储UILabel
和UIColor
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]]