2016-03-27 16 views
0

Es gibt einige Fragen zu diesem Problem. Ich habe alle vorgeschlagenen Antworten ausprobiert, aber bisher hat noch nichts funktioniert. Also ich habe diese func die Angebote ablehnen, die ein Benutzer erhält. Ich kann die Angebote ablehnen und die Zellenzeilen löschen, aber wenn es nur eine Zelle verließ ich fatal error: Index out of range bekommenAufruf deleteRowsAtIndexPaths mehrere Male

func declineButtonTapped(sender: AnyObject) { 
    self.view.userInteractionEnabled = false 
    let buttonRow = sender.tag // this is the tag from my custom cell button 
    let offer = offers[buttonRow] // I get the error here 
    let loadingNotification = MBProgressHUD.showHUDAddedTo(self.view, animated: true) 
    loadingNotification.mode = MBProgressHUDMode.Indeterminate 
    loadingNotification.labelText = "declining offer...." 
    let myUrl = NSURL(string: "\(ipAddress)/api/v1.0/offers.php") 
    let request = NSMutableURLRequest(URL: myUrl!) 
    request.HTTPMethod = "POST" 
    let postString = "id=\(offer.id!)&action=decline&offer_id=\(offer.offer_id!)" 
    request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true) 
    let task = NSURLSession.sharedSession().dataTaskWithRequest(request) 
     { data, response, error in 

      if error != nil { 

       let messageToDisplay = error      
       self.view.userInteractionEnabled = true 

       return 

      } 


      do{ 
       let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary 

       if let parseJSON = json{ 

        let resultValue = parseJSON["status"] as? String 

         if resultValue == "Success"{ 


          dispatch_async(dispatch_get_main_queue()) { 

          print("before count is \(self.offers.count)") // before the error the count is 2 here 
          self.offers.removeAtIndex(buttonRow) //update my model 
          self.tableView.deleteRowsAtIndexPaths([NSIndexPath(forRow: buttonRow, inSection: 0)], withRowAnimation: UITableViewRowAnimation.Fade) 
          print("after count is \(self.offers.count)") //then the count is 1 here  
          MBProgressHUD.hideAllHUDsForView(self.view, animated: true) 

          self.view.userInteractionEnabled = true 

         } 


        }else{ 

         //no success  
       } 
      } 


     } catch{ 

     } 

    } 

    task.resume() 

} 

innerhalb cellForRowAtIndexPath ich den Tag-Wert der Schaltfläche

offerCell.declineButton.tag = indexPath.row 
offerCell.declineButton.addTarget(self, action: #selector(OpenDealsDetailsViewController.declineButtonTapped(_:)), forControlEvents: UIControlEvents.TouchUpInside) 

zuordnen ***** * UPDATE *****

Ich denke, ich habe den Fehler gefunden. Wenn ich print("button row is\(buttonRow)") drucke, wird die Nummer nicht aktualisiert. Also das erste Mal, nennt es die richtige Zeile, aber das zweite Mal ist es die indexPath.row hält es hatte, als declineButtonTapped das erste Mal

button row is0 before count is 2 after count is 1 button row is1 // this of course should be 0 as there is only one cell left fatal error: Index out of range

wenn ich

zu tun versuchen
self.offers.removeAtIndex(buttonRow)         
self.tableView.deleteRowsAtIndexPaths([NSIndexPath(forRow: buttonRow, inSection: 0)], withRowAnimation: UITableViewRowAnimation.Fade) 
self.tableView.reloadData() 

I genannt wurde erhalten folgende Fehlermeldung:

Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).

+0

Was ist der Wert für das Tag, das Ihrer benutzerdefinierten Zelle zugewiesen ist? –

Antwort

1

Sie entweder keine Tags verwendet werden soll, oder Sie Nach jeder Änderung sollte die Tabellenansicht erneut geladen werden. Alternativ könnten Sie die sichtbaren Zellen iterieren und ihre Tag-Werte aktualisieren.

Wenn Sie immer und nur die letzte Zeile aus der Tabelle löschen würden, wäre es in Ordnung. Sobald Sie eine frühere Zeile löschen, haben alle Zeilen danach einen falschen Tag-Wert. Wenn Sie also in die letzte Zeile gehen, ist sie bei diesem Tag nicht vorhanden und alle anderen ungültigen Zeilen führen dazu, dass Sie das falsche Element vom Server löschen.

Ein besserer Ansatz besteht darin, der Zelle eine Instanz einer Klasse zu übergeben, die den Löschvorgang ausführen und mit Details der durchgeführten Aktualisierung zum View-Controller zurückrufen kann. Der View-Controller kann dann seine Datenquelle und die Tabellenansicht aktualisieren. Auf diese Weise trennen Sie den Tabellenindexpfad von der Aktion, die Sie für die Daten ausführen möchten.

+0

natürlich, wenn ich "deleteRowsAtIndexPaths" mit 'reloadData' ändere, bekomme ich den obigen Fehler nicht, aber ich bevorzuge den ersten. Kannst du die letzte von dir vorgeschlagene Option erklären? Kannst du mir bitte die richtige Richtung zeigen? – mat

+0

Der Grund, warum Sie das Tag verwenden, ist, dass es einfach aussieht, die andere Lösung, die ich vorschlage, ist komplexer und schwieriger zu erklären. Als eine erste Ausführung könnten Sie das Datenobjekt an die Zelle übergeben und einen Delegaten von der Zelle zurück zum Controller einrichten, der das Datenobjekt beim Antippen der Schaltfläche übergibt. Dann kann der VC den korrekten aktuellen Indexpfad für dieses Datenelement finden. Mein Hauptvorschlag ist dem ähnlich, benutzt aber eine andere Klasse, um den Code besser zu trennen. – Wain

+0

Danke dafür. Also verwende ich entweder reloadData(), so dass die Tabelle jedes Mal neu geladen wird, wenn ich eine Zelle lösche, oder ich muss einen komplexeren Ansatz verwenden. Da ich ein MVP bin, denke ich, werde ich mich für die leichtere Lösung entscheiden. ;) – mat

Verwandte Themen