2016-02-02 82 views
0

我正在製作一個雞尾酒iOS應用程序。iOS中的更新表視圖(Swift)

我將字符串添加到tableview(「內閣」的一種成分)。用戶輸入一種成分,然後按下ADD按鈕。它成功地將其添加到核心數據中,但它不會立即顯示。我究竟做錯了什麼?

以下是我的代碼,謝謝!

的ViewController:

import UIKit 
import CoreData 

class CabinetViewController: UIViewController, UITextFieldDelegate, UITableViewDataSource, UITableViewDelegate { 

    var ingredientArray = [String]() 
    var display = [String]() 
    var dbIngredients = [String]() 

    let ingredientFetch = NSFetchRequest(entityName: "Cabinet") 
    var fetchedIngredient = [Cabinet]() 

    @IBOutlet weak var TextUI: UITextField! 
    @IBOutlet weak var Button: UIButton! 
    @IBOutlet weak var TableView: UITableView! 

    let moc = DataController().managedObjectContext 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     TextUI.delegate = self 
     TextUI.addTarget(self, action: "textFieldDidChange:", forControlEvents: UIControlEvents.EditingChanged) 

     TableView.delegate = self 
     TableView.dataSource = self 
     TableView.registerClass(UITableViewCell.self, 
      forCellReuseIdentifier: "Cell") 

     // fetch Core Data 
     do{ 
      fetchedIngredient = try moc.executeFetchRequest(ingredientFetch) as! [Cabinet] 
     } catch { 
      fatalError() 
     } 

     let postEndpoint: String = "http://www.thecocktaildb.com/api/json/v1/1/list.php?i=list" 

     guard let url = NSURL(string: postEndpoint) else { 
      print("Error: cannot create URL") 
      return 
     } 

     let urlRequest = NSURLRequest(URL: url) 
     let config = NSURLSessionConfiguration.defaultSessionConfiguration() 
     let session = NSURLSession(configuration: config) 

     let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) in 
      guard let responseData = data else { 
       print("Error: did not receive data") 
       return 
      } 
      guard error == nil else { 
       print("error calling GET on www.thecocktaildb.com") 
       print(error) 
       return 
      } 

      let post: NSDictionary 
      do { 
       post = try NSJSONSerialization.JSONObjectWithData(responseData, 
        options: []) as! NSDictionary 
      } catch { 
       print("error trying to convert data to JSON") 
       return 
      } 

      var count = 1 
      if let drinks = post["drinks"] as? [NSDictionary] { 
       for drink in drinks { 
        if let strIngredient = drink["strIngredient1"] as? String { 
         print(String(count) + ". " + strIngredient) 
         self.dbIngredients.append(strIngredient) 
         count++ 
        } 
       } 
      } 
     }) 
     task.resume() 
     TableView.reloadData() 
    } 

    func textFieldDidChange(textField: UITextField) { 
     search(self.TextUI.text!) 
    } 

    func textField(textField: UITextField, shouldChangeCharactersInRange range: NSRange, replacementString string: String) -> Bool { 
     Button.addTarget(self, action: "buttonPressed:", forControlEvents: .TouchUpInside) 
     return true 
    } 

    func buttonPressed(sender: UIButton!) { 
     //ingredientArray.append(TextUI.text!) 

     let entity = NSEntityDescription.insertNewObjectForEntityForName("Cabinet", inManagedObjectContext: moc) as! Cabinet 
     entity.setValue(TextUI.text!, forKey: "ingredient") 
     do{ 
      try moc.save() 
     }catch { 
      fatalError("failure to save context: \(error)") 
     } 
     showAlertButtonTapped(Button) 
//  dispatch_async(dispatch_get_main_queue(), {() -> Void in 
//   self.TableView.reloadData() 
//  }) 
    } 

    @IBAction func showAlertButtonTapped(sender: UIButton) { 
     // create the alert 
     let alert = UIAlertController(title: "Added!", message: "You've added " + TextUI.text! + " to your cabinet", preferredStyle: UIAlertControllerStyle.Alert) 
     // add an action (button) 
     alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil)) 
     // show the alert 
     self.presentViewController(alert, animated: true, completion: nil) 
    } 

    func search(str:String) { 
     display.removeAll(keepCapacity: false) 

     for s in dbIngredients{ 
      if s.hasPrefix(str){ 
       display.append(s) 
       print(s) 
      } 
     } 
    } 

    func tableView(tableView: UITableView, 
     numberOfRowsInSection section: Int) -> Int { 
      return fetchedIngredient.capacity 
    } 

    func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) 
     do{ 
      let fetchedIngredient = try moc.executeFetchRequest(ingredientFetch) as! [Cabinet] 
      cell.textLabel?.text = fetchedIngredient[indexPath.row].ingredient 
     } catch { 
      fatalError("bad things happened: \(error)") 
     } 
     return cell 
    } 

    func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) { 
     tableView.deselectRowAtIndexPath(indexPath, animated: true) 

     let alert = UIAlertController(title: "Remove " + fetchedIngredient[indexPath.row].ingredient!, 
      message: "No more " + fetchedIngredient[indexPath.row].ingredient! + " in your cabinet?", 
      preferredStyle: .Alert) 

     let deleteAction = UIAlertAction(title: "Remove", 
      style: .Default, 
      handler: { (action:UIAlertAction) -> Void in 
       self.fetchedIngredient.removeAtIndex(indexPath.row) 

       do{ 
        let fetchedResults = try self.moc.executeFetchRequest(self.ingredientFetch) 
        if let result = fetchedResults[indexPath.row] as? NSManagedObject { 
         self.moc.deleteObject(result) 
         try self.moc.save() 
        } 
       }catch{ 
        fatalError() 
       } 
     }) 

     let cancelAction = UIAlertAction(title: "Cancel", 
      style: .Default) { (action: UIAlertAction) -> Void in 
     } 

     alert.addAction(cancelAction) 
     alert.addAction(deleteAction) 

     presentViewController(alert, 
      animated: true, 
      completion: nil) 
     TableView.reloadData() 
    } 


    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 


    /* 
    // MARK: - Navigation 
    // In a storyboard-based application, you will often want to do a little preparation before navigation 
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { 
    // Get the new view controller using segue.destinationViewController. 
    // Pass the selected object to the new view controller. 
    } 
    */ 
} 
+0

後,調用tableView.reloadData() – AMayes

回答

2

因爲你的問題不是你需要使用表視圖beginUpdates和EndUpdates插入該行核心數據。在第

do{ 
    fetchedIngredient = try moc.executeFetchRequest(ingredientFetch) as! [Cabinet] 
    self.tableView.beginUpdates() 
    let totalIngredients = fetchedIngredient.count 
    let newItemIndexPath = NSIndexPath(forRow: totalIngredients-1, inSection: 0) 
    self.tableView.insertRowsAtIndexPaths([newItemIndexPath], withRowAnimation: UITableViewRowAnimation.Automatic) 
    self.tableView.endUpdates() 
} catch { 
    fatalError() 
} 

在你的行數:

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 
    return fetchedIngredient.count 
} 

而就在指數路徑

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) 
    cell.textLabel?.text = fetchedIngredient[indexPath.row].ingredient 
    return cell 
} 
+0

添加該代碼,並得到了錯誤:NSInternalInconsistencyException',原因:'無效更新:第0節中的行數無效。更新(23)後現有節中包含的行數必須等於更新前該節中包含的行數23),加上或減去從該部分插入或刪除的行數(插入1個,刪除0個),加上或減去移入或移出該部分的行數(移入0,移出0)。 – Zach

+0

好的,請檢查編輯答案 – KacosPro

+0

它的工作。謝謝! – Zach

0

有用於該小區排在你的buttonPressed函數的末尾把這個你的代碼有幾個問題。首先,由於您正在將記錄提取到數組中,因此除非更新數組,否則調用reloadData不會產生任何影響。添加新的核心數據記錄和您的fetchedIngredient陣列之間沒有自動連接。

有幾種方法可以解決這個問題,儘管最常見的可能是在覈心數據更新時將記錄重新提取到同一個數組中。或者,您可以將代碼更改爲NSFetchedResultsController而不是數組,當核心數據更新時(基於您提供的謂詞),該數組將自動更新tableView。這個類爲您提供了自動連接到核心數據。

另一個問題是您正在重新提取cellForRowAtIndexPathdidSelectRowAtIndexPath中的記錄。這不應該做。相反,您應該指的是級別級別爲fetchedIngredient的數組(如果您選擇使用該數組,則爲NSFetchedResultsController)。

此外,呼叫dataTaskWithRequest在後臺運行。從代碼中不清楚你是如何使用它的,但事實上你之後有reloadData表明它應該會影響tableView。但是因爲任務在後臺運行,完成處理程序將在重新加載表後運行。因此,您應該在完成處理程序中調用reloadData。而且因爲它然後在另一個線程上運行,就必須將其分派到主隊列,使用:添加按鈕被竊聽

dispatch_async(dispatch_get_main_queue()) { 
    self.tableView.reloadData() 
}