Я хочу иметь NSDictionary
, который отображает от UIView
s к чему-то еще.UIView как словарь ключ?
Однако, поскольку UIViews не реализуют протокол NSCopying
, я не могу использовать их напрямую в качестве ключей словаря.
Я хочу иметь NSDictionary
, который отображает от UIView
s к чему-то еще.UIView как словарь ключ?
Однако, поскольку UIViews не реализуют протокол NSCopying
, я не могу использовать их напрямую в качестве ключей словаря.
Вы можете использовать NSValue
, удерживая указатель на UIView
, и используйте это как ключ. NSValues
можно копировать. но, если представление уничтожено, NSValue
будет содержать указатель нежелательной почты .
Fabulous! Я собирался использовать NSNumber с хешем UIView как int. Думаю, это гораздо приятнее. –
Теперь с ARC вы должны использовать 'valueWithNonretainedObject'. –
@Yar Вот фактический код, в котором используются предложения luvieere и самостоятельно: http://stackoverflow.com/a/11387017/974531 –
Вот фактический код (на основе 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]];
Как проверить, освобождено ли представление или нет? –
Хотя это не совсем то, что они предназначены для, вы могли бы подстегнуть функциональный словарь-подобный интерфейс с помощью 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
* Название, возможно, потребуется некоторая работа.
Вместо того, чтобы хранить указатель на представление и подвергать опасности проблему с мусором, просто дайте тегу UIView и сохраните значение тега в словаре. Гораздо безопаснее.
Я использую простое решение под 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
по мере необходимости. В моем случае представления уже сохранены контроллером представления, в котором я его использую, поэтому я не видел необходимости использовать сильный указатель на них.
NSMapTable также предоставляет это. c.f. '[NSMapTable weakToStrongObjectsMapTable]' – nielsbot
Если вы не нуждаетесь в поддержке до 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.
Это отличное решение! –
простое решение, если вы просто хотите 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]]
Соответствующие: http://stackoverflow.com/questions/1497622/nsmanagedobject-as-nsdictionary-key – kennytm
Это звучит как действительно очень плохая идея. –
Только если вы не знаете о том, что данные могут стать мусором (как указывает принятый ответ). – mrueg