2010-04-01 6 views
6

Ich habe einen Tabellenansicht-Controller mit mehreren UISwitch-Steuerelementen in ihnen. Ich setze den Delegaten mit derselben Aktion für alle Schalter auf den Tabellenansichtscontroller. Ich muss in der Lage sein zu bestimmen, welcher Schalter geändert wurde, also erstelle ich ein Array von Strings, das den Namen jedes Schalters enthält. Die Indizes im Array werden in die Tag-Eigenschaft jedes UISwitch eingefügt.Behandlung mehrerer UISwitch-Steuerelemente in einer Tabellenansicht ohne Verwendung der Tag-Eigenschaft

Ich bin jedoch bereit, die Tag-Eigenschaft für etwas anderes zu verwenden, nämlich das richtige Steuerelement in der Zelle in CellForRowAtIndexPath mit viewWithTag zu finden! (Es gibt mehrere Dinge, die ich in jeder Zelle einstellen muss.)

Also, denke ich hier in der richtigen Richtung? Ich habe das Gefühl, dass ich ziemlich eingeschränkt bin, wie ich genau herausfinden kann, welcher UISwitch seinen Wert verändert hat, damit ich etwas Nützliches damit machen kann.

Antwort

5

Ich reparierte diese durch Subklassen UISwitch wie so:

@interface NamedUISwitch : UISwitch { 
NSString *name; 

}

Es elegant scheint (kein Index-Arrays erforderlich) und die Tag-Eigenschaft ist frei, was es tun will.

ich gelesen, dass Sie mit Subclassing in Objective-C vorsichtig sein, obwohl ...

+0

Ich habe gerade das Gleiche gemacht, mein einziger Kommentar wäre, einen Namen als Eigentum zu machen. – typemismatch

0

Sie sind nah an Ihrem Ansatz. In ähnlichen Situationen habe ich separate UITableViewCell-Unterklassen erstellt, das Tag des UISwitch als index.row des Indexpfads festgelegt und diese UITableViewCell-Unterklasse nur in einem bestimmten Abschnitt der Tabellenansicht verwendet. Dadurch können Sie das Tag der Zelle verwenden, um eindeutig zu bestimmen, in welcher Zelle das Ereignis enthalten ist, ohne eine separate Indexliste zu verwalten (so wie es sich anhört).

Da der Zelltyp eindeutig ist, können Sie einfach auf die anderen Elemente der Zelle zugreifen, indem Sie Methoden/Eigenschaften für die Subklasse UITableViewCell erstellen.

Zum Beispiel:

@interface TableViewToggleCell : UITableViewCell { 
    IBOutlet UILabel *toggleNameLabel; 
    IBOutlet UILabel *detailedTextLabel; 
    IBOutlet UISwitch *toggle; 
    NSNumber *value; 
    id owner; 
} 

@property (nonatomic, retain) UILabel *toggleNameLabel; 
@property (nonatomic, retain) UILabel *detailedTextLabel; 
@property (nonatomic, retain) UISwitch *toggle; 
@property (nonatomic, retain) id owner; 

-(void) setLable:(NSString*)aString; 
-(void) setValue:(NSNumber*)aNum; 
-(NSNumber*)value; 
-(void) setTagOnToggle:(NSInteger)aTag; 

-(IBAction)toggleValue:(id)sender; 

@end 

In:

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
{ 
    // ... prior iniitalization code for creating cell is assumed 
toggleCell.owner = self; 
[toggleCell setLable:@"some string value"]; 
[toggleCell setTagOnToggle:indexPath.row]; 
toggleCell.owner = self; 
return toggleCell; 
    //... handle cell set up for other cell types as needed 
} 

Besitzer ist der Delegierte für die Zelle und kann dann verwendet werden, um Aktionen in Ihrem Controller zu initiieren. Achten Sie darauf, schließen Sie UISwitch zur toggleValue Aktion, so dass Sie Aktionen in den Delegierten initiieren können, wenn die UISwitch Zustand ändert:

-(IBAction)toggleValue:(id)sender; 
{ 
    BOOL oldValue = [value boolValue]; 
    [value release]; 
    value = [[NSNumber numberWithBool:!oldValue] retain]; 
    [owner performSelector:@selector(someAction:) withObject:toggle]; 
} 

Durch die UISwitch mit dem Methodenaufruf geben, können Sie dann auf den Indexpfad für die Zelle. Sie können die Verwendung der Tag-Eigenschaft auch umgehen, indem Sie explizit einen Ivar zum Speichern des NSIndexPath der Zelle und dann zum Weiterleiten der gesamten Zelle mit dem Methodenaufruf verwenden.

+0

Wie über Unterklassifizierung der UISwitch und Hinzufügen einer Zeichenfolge Kennung zu? Wäre das schlechtes Design? – Thaurin

+0

Hmmm, ein Problem mit Ihrem Ansatz ist, dass ich nicht IB benutze, also füge ich alle Steuerelemente zum contentView der Zelle hinzu. Dann, wenn ich sie wieder im Tabellen-Controller brauche, um ihre Werte für die angezeigte Zeile festzulegen, bekomme ich sie mit viewWithTag zurück. Das ist so ziemlich das Problem, weil ich bereits mit dem Tag identifiziere, welcher Schalter geändert wurde. Mit einer NIB verbinden Sie einfach einige Ausgänge. Habe ich hier etwas Wichtiges vermisst? Ich werde jetzt versuchen, UISwitch zu unterklassifizieren, obwohl ich mir nicht sicher bin, ob UISwitch so gebaut wurde, dass er jemals unterklassifiziert wird. – Thaurin

+0

Ich würde empfehlen, in IB einzutauchen und die ganze UITableViewCell zu untergliedern, anstatt nur UISwitch. Es wird (glaube ich) auf lange Sicht zu mehr wartbarem Code führen. Sobald Sie eine Unterklasse über IB/XCode erstellen, wird es wirklich ein Kinderspiel. –

1

ich eine UISwitch Unterklasse mit einem Block basiert hander für Wertänderungssteuerungsereignisse geschrieben haben, die helfen können, wenn zu verfolgen versuchen welcher Wert sich geändert hat Im Idealfall könnten wir etwas Ähnliches mit Komposition statt Subclassing machen, aber das funktioniert gut für meine Bedürfnisse.

https://gist.github.com/3958325

Sie können es wie folgt verwenden:

ZUISwitch *mySwitch = [ZUISwitch alloc] init]; 

[mySwitch onValueChange:^(UISwitch *uiSwitch) { 
     if (uiSwitch.on) { 
      // do something 
     } else { 
      // do something else 
     } 
    }]; 

Sie auch aus einer XIB-Datei verwenden können, durch einen Schalter auf Ihre Ansicht ziehen, und dann ändert seine Klasse ZUISwitch

+0

Dies ist ein großartiger Ansatz, insbesondere für das Iterieren über eine unbekannte Anzahl von Switches. Ich bin neugierig, warum Sie die '[self commonInit]' in watchFromNib sowie init tun. –

0

Mir ist klar, dass ich etwa drei Jahre zu spät zur Party komme, aber ich habe eine Lösung ohne Unterklassen entwickelt, die meiner Meinung nach vorzuziehen ist (und einfacher). Ich arbeite mit genau dem gleichen Szenario wie Thaurins beschriebenes Szenario.

- (void)toggleSwitch:(id) sender 
{ 
    // declare the switch by its type based on the sender element 
    UISwitch *switchIsPressed = (UISwitch *)sender; 
    // get the indexPath of the cell containing the switch 
    NSIndexPath *indexPath = [self indexPathForCellContainingView:switchIsPressed]; 
    // look up the value of the item that is referenced by the switch - this 
    // is from my datasource for the table view 
    NSString *elementId = [dataSourceArray objectAtIndex:indexPath.row]; 
} 

Dann wollen Sie die Methode oben gezeigt erklären, indexPathForCellContainingView. Dies ist eine scheinbar unnötig Methode, weil es auf dem ersten Blick erscheinen würde, dass alles, was Sie tun müssen, ist die Super des Schalters zu identifizieren, aber es gibt einen Unterschied zwischen der superviews von ios7 und früheren Versionen, so dass diese Griffe alle:

- (NSIndexPath *)indexPathForCellContainingView:(UIView *)view { 
    while (view != nil) { 
     if ([view isKindOfClass:[UITableViewCell class]]) { 
      return [self.myTableView indexPathForCell:(UITableViewCell *)view]; 
     } else { 
      view = [view superview]; 
     } 
    } 
    return nil; 
}