ReloadData() nach NSNotificationCenter

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • ReloadData() nach NSNotificationCenter

    Hallo zusammen,

    ich habe ein Problem mit dem Reload meines TableViews. Mir fällt zu diesem Punkt keine Idee mehr ein, wieso das nicht funktioniert.

    Was passiert in meinem Programm:

    1. Im ViewDidLoad meines TableViewControllers instanziiere ich mein Model und hole mir asynchron Daten vom Server für die Tabelle.
    2. Sobald die Daten vollständig geladen und geparst wurden, führe ich die Methode ".postNotificationName" im Model aus.
    3. Im TableViewController reagiert meine Empfänger-Methode richtig auf den NSNotification-Namen.
    4. In dieser Empfänger-Methode führe ich folgendes aus:

    Quellcode

    1. self.tableView.reloadData()
    Dieser Ablauf funktioniert nicht. Ich habe weiterhin eine leere Tabelle. (numberOfSectionsInTableView, numberOfRowsInSection und cellForRowAtIndexPath sind natürlich abhängig von dem instanziierten Modell richtig ausgeprägt)
    Ein Lösungsansatz war die "reloadData"-Methode in einem "dispatch_async(dispatch_get_main_queue()" durchzuführen. ( Auch ein self.viewWillAppear(true) funktioniert nicht )
    Auch damit hatte ich keinen Erfolg.

    Hat mir jemand einen Rat?

    ?(
    lernen, lernen, lernen :)
  • ich hatte so etwas ähnliches mal so gelöst: ich lade zu erst nur soviele daten, dass der tableview gefüllt ist, also die anzeige für den nutzer voll ist. dann lade im hintergrund noch einmal alles und wenn das fertig ist, lasse ich den tableview neu anzeigen mit reloaddata. bekomme den code aus dem kopf nicht mehr hin, ist schon ne weile her. würde mich nochmal melden dazu heute abend.
  • @nussratte: Ich platziere meinen addObserver im ViewDidLoad vor der Instanziierung meines Modells.
    @bastl: sehr gerne würde ich deine Lösung verstehen wollen

    Im Debugger ist mein Model-Objekt nach dem Aufruf der Empfänger-Methode mit allen Werten gefüllt, die ich benötige. Umso mehr verstehe ich nicht, wieso die TableView leer bleibt.


    Mir ist noch folgendes aufgefallen:
    Sobald ich ein Touchevent auf die leere Tabelle ausführe stürzt meine App ab und zeigt einen Exc_bad_acces Fehler im App-Delegate.

    BTW:
    - Im IB sind die Delegates und Datasoucres verbunden.
    - Die Methoden des UITableViewDatasource Protokolls habe ich abhängig von einer Methode des Models gemacht.
    Diese Methode des Modells checkt den/die Status/Bereitschaft der asynchronen Datenbeschaffung. Diese Methode setzt ein Boolean-Wert auf true, wenn
    die Notification ausgeführt wurde. Die Methoden aus dem UITableViewDatasource-Protokoll bekommen als return-Wert also 0 oder die dementsprechende Werte aus dem Model.


    JavaScript-Quellcode: UITableViewController

    1. import UIKit
    2. class BillingPlanTableViewController: UITableViewController {
    3. @IBOutlet weak var menuButton: UIBarButtonItem!
    4. var budgetBillingPlansModel: BudgetBillingPlanModel!
    5. // MARK: - Lifecycle
    6. override func viewDidLoad() {
    7. super.viewDidLoad()
    8. //Menu gesture recognizer
    9. if self.revealViewController() != nil {
    10. menuButton.target = self.revealViewController()
    11. menuButton.action = "revealToggle:"
    12. self.view.addGestureRecognizer(self.revealViewController().panGestureRecognizer())
    13. }
    14. //initialize BudgetBillingPlansModel
    15. NSNotificationCenter.defaultCenter().addObserver(self, selector: "initBbPDone:",name:"initBbPDone", object: nil)
    16. budgetBillingPlansModel = BudgetBillingPlanModel()
    17. println(budgetBillingPlansModel)
    18. }
    19. // MARK: - Custom Methods
    20. func initBbPDone(notification: NSNotification){
    21. //reload tableview: from in thread: Zu diesem Zeitpunkt ist mein Objekt gefüllt.
    22. dispatch_async(dispatch_get_main_queue(),{
    23. self.tableView.reloadData()
    24. });
    25. }
    26. // MARK: - Table view data source
    27. override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
    28. if(self.budgetBillingPlansModel.checkBbPisReady()){
    29. return self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray().count
    30. }else{
    31. return 0
    32. }
    33. }
    34. override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    35. if(self.budgetBillingPlansModel.checkBbPisReady()){
    36. var numberOfRowsInSection: Int = 0
    37. for(var index = 0; index < self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray().count; index++){
    38. if(index == section){
    39. numberOfRowsInSection = self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray()[index].getSubPlan().count
    40. }
    41. }
    42. return numberOfRowsInSection
    43. }else{
    44. return 0
    45. }
    46. }
    47. override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    48. let cell = tableView.dequeueReusableCellWithIdentifier("budgetBillingPlans", forIndexPath: indexPath) as! BudgetBillingPlanTableViewCell
    49. if(self.budgetBillingPlansModel.checkBbPisReady()){
    50. //section == bbP Array
    51. for(var i = 0; i < self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray().count; i++){
    52. if(i == indexPath.section){
    53. //row == subPlans Array
    54. let subPlans: [SubPlan] = self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray()[i].getSubPlan()
    55. for(var j = 0; j < subPlans.count; j++){
    56. if(j == indexPath.row){
    57. cell.ibo_header.text = "\(self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray()[i].getSubPlan()[j].getSbbpDivisionName())"
    58. cell.ibo_budgetAmount.text = "\(self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray()[i].getSubPlan()[j].getSbbpActAmount())"
    59. cell.ibo_contract.text = "\(self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray()[i].getSubPlan()[j].getSbbpContractNumber())"
    60. cell.ibo_date.text = (self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray()[i].getFirstAdjustmentDate()) + " " + (self.budgetBillingPlansModel.getBudgetBillingPlanModel()!.getBbpArray()[i].getbbpCycleName())
    61. }
    62. }
    63. }
    64. }
    65. }else{
    66. }
    67. return cell
    68. }
    69. override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat {
    70. return 150
    71. }
    72. }
    Alles anzeigen
    lernen, lernen, lernen :)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von imoney91 ()

  • Danke für das Feedback.

    Was bedeutet das denn konkret für mein Problem? So wie ich euch verstanden habe müssen alle Interaktionen zum UI in der Main abgearbeitet werden.

    Wenn ich mein eigenes Coding verstehe, passiert das ja auch:
    Sobald meine asynchrone Datenbeschaffung im Thread x durchgelaufen ist, wird eine Notification getriggert und anschließend führe ich ein reloadData in der Main aus.
    Dennoch bleibt die Tabelle leer. Soll ich etwa alle Instruktionen in dem UITableViewDelegate/Datasource-Protokoll in eine main_queue packen?
    lernen, lernen, lernen :)
  • Also es ist natürlich ein Fehler. So wie ich dich verstanden habe, berechnest du die Daten im Hintergrund (aka != Main-Thread) und schickst dan eine Notifikation. Der Observer der Notification wird in demjenigen Thread ausgeführt, in dem die Notifikation gepostet wurde (aka != Main-Thread). Der dispatchAsynch() muss also in jedem Falle herein. Wenn es dann immer noch nicht funktioniert, dann hast du eben zwei Fehler.

    Ich sehe da zu wenig Code. Außerdem: Wird die Notifikation nicht gefangen? Wird sie gefangen, aber der Block nicht ausgeführt? Wird der Block ausgeführt, aber es passiert einfach nichts? Was sagt der Debugger im Block, wenn du self und self.tableView anzeigen lässt?
    Es hat noch nie etwas gefunzt. To tear down the Wall would be a Werror!
    25.06.2016: [Swift] gehört zu meinen *Favorite Tags* auf SO. In welcher Bedeutung von "favorite"?
  • Die Notifikation wird aufjedenfall in meinem selector gefangen. Den dispatchAsync() habe ich bereits in meinem selector ausgeprägt und dieser führt auch mein reloadData() aus.

    Zu deinen Fragen:
    - die Notifikation wird gefangen
    - der Dispatch-Block wird ausgeführt
    - das folgende Screenshot zeigt folgende Konstellation im Debugger

    Bildschirmfoto 2015-06-16 um 21.20.53.png
    • Dabei fällt mir aber auf, dass ich im "self" kein tableView sehe
    • ein "println(self.tableview)" zeigt in der Konsole aber einen validen TableView
    • Mein Objekt "budgetBillingPlan" ist zu diesem Zeitpunkt nicht nil also gültig ( bbpArray[0] und subPlan[3] )


    Anbei habe ich noch relevante Methoden aus meiner Model-Klasse eingefügt:

    JavaScript-Quellcode

    1. class BudgetBillingPlanModel: NSObject {
    2. var budgetBillingPlan: BudgetBillingPlan!
    3. var bbPisReady: Bool!
    4. .
    5. .
    6. .
    7. //getBudgetBillingPlans
    8. private func getBudgetBillingPlans(){
    9. Alamofire.request(.GET, Constants.service_getBudgetBillingPlans)
    10. .responseString { (request, response, jsonString, error) in
    11. println(error)// error ist im debugger-Zeitpunkt == nil
    12. self.budgetBillingPlan = self.parseServerResponse(jsonString!)
    13. self.setbbPisReady()
    14. }
    15. }
    16. .
    17. .
    18. .
    19. //Notifications
    20. private func setbbPisReady(){
    21. self.bbPisReady = true
    22. //object controller has to implement the notification method with "initBbPDone"
    23. NSNotificationCenter.defaultCenter().postNotificationName("initBbPDone", object: nil)
    24. }
    25. .
    26. .
    27. .
    28. //check status
    29. func checkBbPisReady()->Bool{
    30. if(self.bbPisReady == true){
    31. return true
    32. }else{
    33. return false
    34. }
    35. }
    36. .
    37. .
    38. .
    39. //getter
    40. func getBudgetBillingPlanModel()->BudgetBillingPlan?{
    41. if(self.checkBbPisReady()){
    42. return self.budgetBillingPlan
    43. }else{
    44. return nil
    45. }
    46. }
    Alles anzeigen
    lernen, lernen, lernen :)
  • Hallo zusammen,

    da ich für dieses Problem in absehbarer Zeit kein Bugfix finden konnte habe ich das Notifications-Verfahren verworfen. Stattdessen habe ich für die Kommunikation im MVC nun das KVO Verfahren genutzt.
    Nun funktioniert das Füllen meines TableViews.
    lernen, lernen, lernen :)

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von imoney91 ()