TableView IndexPath Speicherproblem

  • TableView IndexPath Speicherproblem

    Hallo, ich habe folgendes Problem.
    Ich möchte eine TableView zum abhacken erstellen. Das klappt auch alles sehr gut. Nun habe ich aber ein Problem mit folgender Methode:

    Quellcode

    1. -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath*) newIndexPath{
    2. if (![[tableView cellForRowAtIndexPath:newIndexPath] accessoryType] == UITableViewCellAccessoryCheckmark){
    3. [[tableView cellForRowAtIndexPath:newIndexPath] setAccessoryType:UITableViewCellAccessoryCheckmark];
    4. }


    Diese Methode checkt nicht nur, die zelle am indexPath sondern auch andere einträge. Scoll ich in meinem Table weiter nach unten sind auch dort zellen gecheckt.
    Es hat den anschein als ob 10zellen in den speicher geladen werden. check ich nun die erse zeile ist 1,11,21... gecheckt. check ich die 2 zelle sind 2,12,22 geckeckt usw...
    Ich denke ich mach irgendetwas mit der Speicherverwaltung falsch.
    Kann mir jemand weiterhelfen?
  • Die Tabelle kann 10 Zeilen aufs mal darstellen (bei Default-Höhe). Da die Tabellenzellen recycled werden (reusable...) wird, wenn du nach unten scrollst, die oben rausgescrollte Zelle für die nächste von unten verwendet, und wenn diese gecheckt war ist nun diese auch gecheckt, darum dein 10er Interval.

    Lösung: in der tableCellFor... Delegate Methode den accessory-view immer entsprechend setzen.
    Widgetschmie.de • Life is too short for gadgets
  • Original von Pascal
    Die Tabelle kann 10 Zeilen aufs mal darstellen (bei Default-Höhe). Da die Tabellenzellen recycled werden (reusable...) wird, wenn du nach unten scrollst, die oben rausgescrollte Zelle für die nächste von unten verwendet, und wenn diese gecheckt war ist nun diese auch gecheckt, darum dein 10er Interval.

    Lösung: in der tableCellFor... Delegate Methode den accessory-view immer entsprechend setzen.


    so was in der Art hatte ich mir gedacht, nur leider kann ich mit deinem Lösungsansatz nichts anfangen, sorry bin echt noch totaler anfänger.
    Wärst du so nett und könntest die Lösung noch etwas ausführen.
  • Klar. :)
    Du hast ja in deiner Tableview-Delegate die Methode cellForRowAtIndexPath: (o.ä., bin grad am iPhone unterwegs). Wie sieht die aus? Dort musst du den Accessory-View setzen, entweder als checkmark oder eben nicht.
    Widgetschmie.de • Life is too short for gadgets
  • das ist ja auch das komische, hier tritt der gleiche Effekt auf, die sieht so aus:

    Quellcode

    1. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    2. NSInteger row = [indexPath row];
    3. NSInteger section = [indexPath section];
    4. static NSNumberFormatter *numberFormatter = nil;
    5. if (numberFormatter == nil) {
    6. numberFormatter = [[NSNumberFormatter alloc] init];
    7. [numberFormatter setNumberStyle:NSNumberFormatterNoStyle];
    8. }
    9. static NSString *CellIdentifier = @"Cell";
    10. UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    11. if (cell == nil) {
    12. cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    13. UITableViewCellStyleSubtitle;
    14. }
    15. // Get the event corresponding to the current index path and configure the table view cell.
    16. Nahrung *nahrung = (Nahrung *)[[gruppenArray objectAtIndex:section]objectAtIndex:row];
    17. cell.textLabel.adjustsFontSizeToFitWidth;
    18. cell.textLabel.text = [nahrung name];
    19. NSNumberFormatter *formatter = [[NSNumberFormatter new] autorelease];
    20. cell.detailTextLabel.text =[NSString stringWithFormat:@"Fettpunkte: %@ ",[formatter stringFromNumber:nahrung.fettpunkte ]];
    21. if (eventController) {
    22. for (int i = 0; i < [eventController.nahungSelectedArray count]; i++){
    23. Nahrung *nahrungSel = (Nahrung *)[eventController.nahungSelectedArray objectAtIndex:i];
    24. if ([nahrungSel.name isEqualToString:nahrung.name]){
    25. cell.accessoryType = UITableViewCellAccessoryCheckmark;
    26. }
    27. }
    28. }
    29. return cell;
    30. }
    Alles anzeigen


    obwohl die if-abfrage (f ([nahrungSel.name isEqualToString:nahrung.name]) nicht zutrifft sind einträge gehackt.
    darauß schließe ich, dass es eine delegate oder so was für den Accessory geben muss der AccessoryCheckmark für einen bestimmten index path gespeichter hat.
  • Original von j-ckruse
    Hi,

    ich bin gerade nicht an meinem Mac, aber teste mal das verhalten, wenn du ein "else" einbaust und da drin einen anderen accessoryType festlegst.

    Wie gesagt, ich kann es gerade selber leider nicht testen.


    ich weiß zwar nicht warum, aber es geht! super!!!! 1000 Dank!
  • Original von Lude
    ich weiß zwar nicht warum, aber es geht! super!!!! 1000 Dank!

    Es geht aus dem Grund welchen ich dir versucht habe zu erklären. Jede 10. Zelle hat den accessory Type gesetzt weil die Zelle recycelt wird und du die Chechbox vorhin nur gesetzt, aber nicht entfernt hast wenn nötig. Das ELSE tut das nun. ;)

    Edit:
    Du solltest dein Modell nochmal überdenken, diese Schleife wo du checkst ob die Checkmark gesetzt werden soll ist Ressourcenfressend. Eine property ist bestimmt sauberer. ;)

    Edit2:
    Wieso machst du einen numberFormatter welchen du nicht benutzst? Das adjustsFontsize tut ebenfalls nichts. Und wenn du deine Loop behalten willst, nimm doch wenigstens Fast-Enumeration. :)
    Widgetschmie.de • Life is too short for gadgets
  • Original von Pascal
    Original von Lude
    ich weiß zwar nicht warum, aber es geht! super!!!! 1000 Dank!

    Es geht aus dem Grund welchen ich dir versucht habe zu erklären. Jede 10. Zelle hat den accessory Type gesetzt weil die Zelle recycelt wird und du die Chechbox vorhin nur gesetzt, aber nicht entfernt hast wenn nötig. Das ELSE tut das nun. ;)

    Edit:
    Du solltest dein Modell nochmal überdenken, diese Schleife wo du checkst ob die Checkmark gesetzt werden soll ist Ressourcenfressend. Eine property ist bestimmt sauberer. ;)

    Edit2:
    Wieso machst du einen numberFormatter welchen du nicht benutzst? Das adjustsFontsize tut ebenfalls nichts. Und wenn du deine Loop behalten willst, nimm doch wenigstens Fast-Enumeration. :)


    also ich hab es mal versucht deinen Vorschlag umzusetzen. Bin jedoch kläglich gescheitert.
    Meine Idee war so, ich erzeuge einen neuen datentyp ChecktNahrung der von Nahrung erbt.

    Quellcode

    1. #import "Nahrung.h"
    2. @interface ChecktNahrung : Nahrung {
    3. Boolean checkt;
    4. }
    5. @property Boolean checkt;
    6. @end


    aber irgendwas mache ich hier falsch. Möchte ich checkt setzen:

    nahrung = [nahrungAr objectAtIndex:i];
    nahrung.checkt = FALSE[/PHP]

    Quellcode

    1. ChecktNahrung *nahrung = [[ChecktNahrung alloc] init];
    2. nahrung = [nahrungAr objectAtIndex:i];
    3. nahrung.checkt = FALSE


    stürtzt das Programm mit folgender Fehlermeldung ab:
    2009-11-20 18:24:59.206 Locations[18232:207] Failed to call designated initializer on NSManagedObject class 'ChecktNahrung'
    2009-11-20 18:25:00.455 Locations[18232:207] *** -[NSManagedObject setCheckt:]: unrecognized selector sent to instance 0x4b58610
    2009-11-20 18:25:00.456 Locations[18232:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSManagedObject setCheckt:]: unrecognized selector sent to instance 0x4b58610'
  • Ich lege dir nahe, einführende Literatur zu lesen. Du wirst sehen, programmieren in Obj-C wird dir danach 1000x mehr Freude bereiten:
    • Der Datentyp heisst "BOOL", nicht "Boolean"
    • Es heisst "NO", nicht "FALSE"
    • Du hast wahrscheinlich das synthesize vergessen
    Und das ist jetzt erst der Kommentar zu deinem Header-Code für "ChecktNahrung". ;)

    Also: Du sollst ja keine Subklasse erstellen, sondern lediglich deiner Nahrung (welche ja sicher Properties wie "name" hat) eine weitere property "checked" hinzufügen. Das machst du so:

    Nahrung.h

    Quellcode

    1. ...
    2. @interface Nahrung : DeineSuperklasse_wahrscheinlichNSManagedObject_lautFehlermeldung
    3. {
    4. ...
    5. BOOL checked;
    6. ...
    7. }
    8. ...
    9. @property (nonatomic, assign) BOOL checked;
    10. ...
    11. @end
    Alles anzeigen


    Nahrung.m

    Quellcode

    1. ...
    2. @implementation Nahrung
    3. // deinde anderen Properties
    4. @synthesize checked;
    5. ...
    6. // alle deine Methoden
    7. ...
    8. @end


    Soweit so gut. Wenn nun jemand eine Tabellenzelle antappt, dann machst du das wohl in der tableView:didSelectRowAtIndexPath:

    Quellcode

    1. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
    2. {
    3. // hier bitte noch error checking
    4. Nahrung *selectedNahrung = [nahrungsArray objectAtIndex:indexPath.row]; // angenommen du hast einen 1-dimensionalen array
    5. selectedNahrung.checked = !selectedNahrung.checked;
    6. }


    Wenn du nun nur die ausgewählte Nahrung willst, dann gehst du einfach deinen nahrungsArray durch und steckst jede Nahrung, welche checked == YES hat, in einen neuen mutable Array und gibst den zurück.

    Viel Spass :)
    Widgetschmie.de • Life is too short for gadgets
  • puuh, hab das jetzt alles so gemacht.

    Bekomme aber sobald ich auf die cheked propertie zugreife immer noch diese Fehlermeldung:
    2009-11-23 09:03:24.588 Locations[2395:207] *** -[NSManagedObject checked]: unrecognized selector sent to instance 0x4d5f310
    2009-11-23 09:03:24.589 Locations[2395:207] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSManagedObject checked]: unrecognized selector sent to instance 0x4d5f310'

    Quellcode

    1. @interface Nahrung : NSManagedObject
    2. {
    3. BOOL checked;
    4. }
    5. @property (nonatomic, retain) NSString * gruppe;
    6. @property (nonatomic, retain) NSNumber * fettpunkte;
    7. @property (nonatomic, retain) NSString * name;
    8. @property (nonatomic, retain) NSString * portionierung;
    9. @property (nonatomic, retain) NSSet * selectierteNahrungen;
    10. @property (nonatomic, assign) BOOL checked;
    11. @end
    Alles anzeigen


    Quellcode

    1. #import "Nahrung.h"
    2. #import "SelectierteNahrung.h"
    3. @implementation Nahrung
    4. @dynamic gruppe;
    5. @dynamic fettpunkte;
    6. @dynamic name;
    7. @dynamic portionierung;
    8. @dynamic selectierteNahrungen;
    9. @synthesize checked;
    10. @end
    Alles anzeigen


    Quellcode

    1. for (int i = 0; i < [nahrungAr count]; i++) {
    2. Nahrung *nahrung = [nahrungAr objectAtIndex:i];
    3. nahrung.checked = NO;


    Aber echt mal DANKE für deine geduld und mühen.
  • Anscheinend hast du keine Nahrungs-Objekte in deinem Array "nahrungAr". Mach mal folgendes, gleich vor dieser for-Schleife, und zeig was da kommt:

    Quellcode

    1. NSLog(@"Object 0: %@", [nahrungAr objectAtIndex:0]);
    Widgetschmie.de • Life is too short for gadgets
  • Original von Pascal
    Das sind aber Objekte vom Typ "NSManagedObject", nicht von deiner "Nahrung"sklasse drin. ;)


    aber hier:

    Nahrung *nahrung = [nahrungAr objectAtIndex:i];

    erstell ich doch dann welche Objekte vom Typ Nahrung, oder nicht?
    und danach wird ja der Fehler geworfen.