2010-06-07 3 views
27

Я хочу иметь NSDictionary, который отображает от UIView s к чему-то еще.UIView как словарь ключ?

Однако, поскольку UIViews не реализуют протокол NSCopying, я не могу использовать их напрямую в качестве ключей словаря.

+1

Соответствующие: http://stackoverflow.com/questions/1497622/nsmanagedobject-as-nsdictionary-key – kennytm

+0

Это звучит как действительно очень плохая идея. –

+0

Только если вы не знаете о том, что данные могут стать мусором (как указывает принятый ответ). – mrueg

ответ

30

Вы можете использовать NSValue, удерживая указатель на UIView, и используйте это как ключ. NSValues можно копировать. но, если представление уничтожено, NSValue будет содержать указатель нежелательной почты .

+0

Fabulous! Я собирался использовать NSNumber с хешем UIView как int. Думаю, это гораздо приятнее. –

+7

Теперь с ARC вы должны использовать 'valueWithNonretainedObject'. –

+0

@Yar Вот фактический код, в котором используются предложения luvieere и самостоятельно: http://stackoverflow.com/a/11387017/974531 –

17

Вот фактический код (на основе the answer by luvieere и еще одно предложение по Яру):

// 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]]; 
+0

Как проверить, освобождено ли представление или нет? –

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 

* Название, возможно, потребуется некоторая работа.

1

Вместо того, чтобы хранить указатель на представление и подвергать опасности проблему с мусором, просто дайте тегу UIView и сохраните значение тега в словаре. Гораздо безопаснее.

0

Я использую простое решение под ARC, предоставляемое Objective-C++.

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 по мере необходимости. В моем случае представления уже сохранены контроллером представления, в котором я его использую, поэтому я не видел необходимости использовать сильный указатель на них.

+1

NSMapTable также предоставляет это. c.f. '[NSMapTable weakToStrongObjectsMapTable]' – nielsbot

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 был введен в прошивке 6.

+0

Это отличное решение! –

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]] 

 Смежные вопросы

  • Нет связанных вопросов^_^