2010-06-07 9 views
27

Ich möchte ein NSDictionary haben, die auf etwas anderes aus UIView s abbildet.UIView als Wörterbuchschlüssel?

Da jedoch UIViews nicht das NSCopying Protokoll implementieren, kann ich sie nicht direkt als Dictionary-Schlüssel verwenden.

+1

Relevant zu speichern: http://stackoverflow.com/questions/1497622/nsmanagedobject-as-nsdictionary-key – kennytm

+0

Das klingt nach einer wirklich sehr schlechten Idee. –

+0

Nur, wenn Sie nicht wissen, dass die Daten zu Müll werden könnten (wie die akzeptierte Antwort darauf hinweist). – mrueg

Antwort

30

Sie können einen NSValue verwenden, der den Zeiger auf UIView hält und diesen als Schlüssel verwendet. NSValues sind kopierbar. aber, wenn die Ansicht zerstört wird, halten die NSValue einen Junk-Zeiger. Hier

+0

Fabulous! Ich war dabei, eine NSNumber mit dem UIView-Hash als int zu verwenden. Das ist viel schöner, denke ich. –

+7

Jetzt mit ARC müssen Sie 'valueWithNonretainedObject' verwenden. –

+0

@Yar Hier ist der eigentliche Code mit Vorschlägen von luviere und dir: http://StackOverflow.com/a/11387017/974531 –

17

ist der eigentliche Code (basierend auf the answer by luvieere und weiterer Vorschlag von 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]]; 
+0

Wie kann ich überprüfen, ob die Ansicht freigegeben wurde oder nicht? –

4

Obwohl dies nicht wirklich das, was sie für bestimmt sind, könnten Sie eine funktionelle Wörterbuch-ähnliche Oberfläche Peitsche Associative References mit:

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); 
} 

Man könnte sogar diese in einer Klasse einpacken ThingWhatActsLikeADictionaryButWithKeysThatArentCopyable *; In diesem Fall sollten Sie die Ansichten beibehalten, die Sie als Schlüssel verwenden.

So etwas wie diese (nicht getestet):

#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 

* Der Name etwas Arbeit benötigen.

1

Anstatt speichern einen Zeiger auf die Ansicht und riskieren, den Müll Problem, geben Sie einfach die UIView einen Tag und den Wert des Tags im Wörterbuch. Viel sicherer.

0

Ich verwende eine einfache Lösung unter ARC von Objective-C++ zur Verfügung gestellt.

MyClass.mm:

#import <map> 

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

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

In diesem Beispiel habe ich, indem alle Werte stärker Typprüfung bin immer haben eine UIColor* sein, die alles, was ich dies für erforderlich ist. Aber man könnte auch id als Werttyp verwenden, wenn Sie ein beliebiges Objekt als Wert, ab zulassen möchten: std::map<UIView* __weak, id __strong> viewMap; Ebenso für Schlüssel: id __weak, id __strong> viewMap;

Sie können auch variieren die __strong und __weak Attribute nach Bedarf. In meinem Fall werden die Ansichten vom View-Controller, in dem ich diesen benutze, bereits beibehalten, sodass ich keinen starken Zeiger darauf sehen musste.

+1

NSMapTable bietet dies auch. c.f. '[ – nielsbot

4

Sofern Sie vor iOS 6 keine Unterstützung benötigen, funktioniert NSMapTable (empfohlen von neilsbot) gut, da es einen Enumerator über die Schlüssel in der Auflistung bereitstellen kann. Das ist nützlich für Code, der allen Textfeldern gemeinsam ist, wie das Festlegen des Delegaten oder das bidirektionale Synchronisieren der Textwerte mit einer NSUserDefaults-Instanz.

in 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; 
} 

in viewWillAppear:

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

in 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; 

Und jetzt werde ich weinen, weil ich all dies umgesetzt bevor ich feststelle, dass meine iOS 5.1-zielgerichtete App es nicht nutzen kann. NSMapTable in iOS eingeführt wurde 6.

+0

Dies ist eine großartige Lösung! –

0

eine einfache Lösung, wenn Sie nur wollen, UIView als Schlüssel gelegentlich, ich benutze es UILabel und 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]] 
Verwandte Themen