2017-08-28 64 views
0

我有一个表格视图。当我点击一个单元格时,它会将我带到一个页面,在该页面中我可以编辑数据并传递单元格中的所有信息。然后我可以点击“保存”/“删除”,并将更改发布到/从firebase中删除该项目。然后它将我带回表格视图并提取最新更新的Firebase数据。功能触发先前打开的VC

问题

但是,如果我删除的项目(该页面,在这里我可以编辑/删除细节上),然后得到转变回表视图,然后在不同的细胞和编辑和保存它将编辑的项目发布到先前删除的项目。这对我来说甚至是没有意义的。

调查

我试图删除的项目,造成应用程序,重新打开然后保存不同的小区。在这种情况下,错误不会发生。这导致我相信可能存在某种内存/内存泄漏问题,但我不知道如何才能真正解决此问题。

我尝试

视图控制器与TableView中

import UIKit 
import Firebase 

class ItemListVC: UIViewController, UITableViewDelegate, UITableViewDataSource, UIPickerViewDelegate { 

    //reference to firebase database 
    var ref : DatabaseReference? 
    var handle : DatabaseHandle? 
    var allItemData : [String:Any] = [:] 
    // Get current userID 
    let userID = (Auth.auth().currentUser?.uid) ?? "" 
    // Outlets 
    @IBOutlet weak var addItemOutlet: UIButton! 
    @IBOutlet weak var tableView: UITableView! 
    @IBOutlet weak var numberOfItemsTextBox: UITextField! 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Set up tableView 
     tableView.delegate = self 
     tableView.dataSource = self 
     tableView.rowHeight = 69 
     // Set up UIPickerView (dropdown for numberOfItemsTextBox) 
     setUpPickers() 
    } 

    override func viewDidAppear(_ animated: Bool) { 
     super.viewDidAppear(animated) 
     // fetch user's item data from firebase 
     ref = Database.database().reference() 
     handle = ref?.child("users").child(userID).child("items").observe(DataEventType.value, with: { (snapshot) in 
      // replace the old array 
      self.allItemData = snapshot.value as? [String : AnyObject] ?? [:] 
      // reload the UITableView 
      self.tableView.reloadData() 
      self.setEnableForAddOutlet() 
     }) 
     // Get numberOfItems 
     ref.child("user/" + userID + "/items/numberOfItems").observeSingleEvent(of: .value, with: { (snapshot) in 
      if snapshot.value is NSNull { 
       self.numberOfItemsTextBox.text = "" 
      } else { 
       // successfully fetched value 
       value = (snapshot.value as? NSDictionary)! 
       self.numberOfItemsTextBox.text = numberOfItems 
      } 
     }) 
    } 

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

    func save() { 
     print("post the value for numberOfItems to firebase") 
     let itemsToPost : [String: Any] = [ 
      "numberOfItems" : numberOfItemsTextBox.text ?? "", 
     ] 
     for item in items { 
      self.ref.child("users/" + userID + "/items").child(item.key).setValue(item.value) 
     } 
    } 

    // Action when the return key pressed 
    func textFieldShouldReturn(_ textField: UITextField) -> Bool { 
     print("running textFieldShouldReturn") 
     textField.resignFirstResponder() 
     return true 
    } 

    func setEnableForAddOutlet() { 
     if (allItemData.count > 1) { 
      addItemOutlet.isEnabled = false 
     } else { 
      addItemOutlet.isEnabled = true 
     } 
    } 

    //////////////// 
    // BUTTONS 
    @IBAction func addItemButtonPressed(_ sender: Any) { 
     // Save 
     save() 
     performSegue(withIdentifier:"ItemAdd", sender: nil) 
    } 

    @IBAction func nextButtonPressed(_ sender: Any) { 
     // Save 
     save() 
     performSegue(withIdentifier:"mySegueToADifferentPlace", sender: nil) 
    } 

    @IBAction func doneButtonPressed(_ sender: Any) { 
     // Save 
     save() 
     performSegue(withIdentifier:"mySegueToSomeWhereElse", sender: nil) 
    } 

    @IBAction func backButtonPressed(_ sender: Any) { 
     // Save 
     save() 
     performSegue(withIdentifier:"mySegueToSomeWhereElse", sender: nil) 
    } 

    // End of [BUTTONS] 
    //////////////// 

    //////////////// 
    // TABLE VIEW 

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

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
     let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! itemListCell 
     let key = Array(allItemData.keys)[indexPath.row] 
     let item = (allItemData[key] as? [String:Any]) ?? [:] 
     let name = (item["name"] as? String) ?? "" 
     let year = (item["year"] as? String) ?? "" 
     cell.titleLabel?.text = name 
     cell.itemID = key 
     cell.name = name 
     cell.year = year 
     cell.other = (item["other"] as? String) ?? "" 
     cell.state = (item["state"] as? String) ?? "" 

     return cell 
    } 

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath){ 
     performSegue(withIdentifier:"ItemEdit", sender: nil) 
    } 

    // End of [TABLE VIEW] 
    //////////////// 


    ////////// 
    // Picker Controllers 


    //Arrays for picker views 
    let numOfItemsArray = ["0", "1", "2", "2+"] 
    let errorArray = ["unable to load"] 

    let itemPickerView = UIPickerView() 

    func setUpPickers() { 
     print("running setUpPickers") 
     // new picker 
     itemPickerView.delegate = self 
     numberOfItemsTextBox.inputView = itemPickerView 
    } 

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 
     print("setting titleForRow...") 
     if pickerView == itemPickerView { 
      return numOfItemsArray[row] 
     } else { 
      return errorArray[0] 
     } 
    } 

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
     print("setting numberOfRowsInComponent...") 
     if pickerView == itemPickerView { 
      return numOfItemsArray.count 
     } else { 
      return errorArray.count 
     } 
    } 

    func numberOfComponents(in pickerView: UIPickerView) -> Int{ 
     print("setting numberOfComponents...") 
     return 1 
    } 

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 
     print("setting didSelectRow...") 

     if pickerView == itemPickerView { 
      //change the text in the textField equal to the selection 
      let value = numOfItemsArray[row] 
      numberOfItemsTextBox.text = value 
      if value == numOfItemsArray[0] { 
       numberOfItemsTextBox.textColor = UIColor.lightGray 
      } else { 
       numberOfItemsTextBox.textColor = UIColor.black 
      } 
     } 
     numberOfItemsTextBox.resignFirstResponder() 
    } 

    // 
    ////////// 


    /////////////////// 
    //MARK: - Navigation 
    //In a storyboard-based application, you will often want to do a little preparation before navigation 
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) { 
     if segue.identifier == "ItemEdit" { 
      // get the indexPath of the selected cell 
      if let indexPath = tableView.indexPathForSelectedRow { 
       // get the selected cell 
       let cell = tableView.cellForRow(at: indexPath) as! itemListCell 
       // get an instance of the next ViewController 
       let itemController : EditVC = segue.destination as! EditVC 
       // take all the data from the selected cell and pass it to the next ViewController 
       print("itemController variables") 
       itemController.itemID = cell.itemID 
       itemController.name = cell.name 
       itemController.year = cell.year 
       itemController.other = cell.other 
       itemController.state = cell.state 
      } else { 
       // tell the user if the indexPath of the selected cell cannot be retrieved 
       print("Unable to select item") 
      } 
     } 
    } 
    ////////////////// 
} 

的ViewController编辑/删除

import UIKit 
import Firebase 

class EditVC: UIViewController, UIPickerViewDelegate { 

    @IBOutlet weak var scrollView: UIScrollView! 
    @IBOutlet weak var nameTextField: UITextField! 
    @IBOutlet weak var yearTextField: UITextField! 
    @IBOutlet weak var otherTextField: UITextField! 
    @IBOutlet weak var stateTextField: UITextField! 

    // Variables for items's Details 
    var itemID = "" 
    var name = "" 
    var year = "" 
    var other = "" 
    var state = "" 

    let userID = Auth.auth().currentUser!.uid 
    let ref = Database.database().reference() 


    override func viewDidLoad() { 
     super.viewDidLoad() 
     self.hideKeyboardWhenTappedAround() 
     //for shifting textFields when keyboard covers 
     NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name:NSNotification.Name.UIKeyboardWillShow, object: nil) 
     NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name:NSNotification.Name.UIKeyboardWillHide, object: nil) 

     setUpPickers() 

     // Set initial values for TextFields 
     nameTextField.text = name 
     yearTextField.text = year 
     otherTextField.text = other 
     stateTextField.text = state 
    } 

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

    ///////////////////////// 
    // Buttons 
    @IBAction func returnButtonPressed(_ sender: Any) { 
     save() 
     performSegue(withIdentifier: "backToTableView", sender: self) 
    } 

    @IBAction func deleteButtonPressed(_ sender: Any) { 
     if itemID != "" { 
      print("removing item") 
      self.ref.child("users").child(userID).child("items").child(itemID).removeValue(); 
     } 
     performSegue(withIdentifier: "backToTableView", sender: self) 
    } 

    @IBAction func doneButton(_ sender: Any) { 
     save() 
     performSegue(withIdentifier: "backToTableView", sender: self) 
    } 
    // End of [Buttons] 
    ///////////////////////// 

    func save() { 
     // Create an items object to post 
     // Get the values from all textfields and set in the object 
     let itemsToPost : [String: Any] = [ 
      "name": nameTextField.text ?? "", 
      "year": yearTextField.text ?? "", 
      "state": stateTextField.text ?? "", 
      "other": otherTextField.text ?? "" 
     ] 
     // if the user is saving a new item (itemID == ""), then create a new ID and set itemID 
     if (itemID == "") { 
      itemID = ref.child("users/" + userID + "/items").childByAutoId().key 
     } 
     // post the items object to firebase 
     for item in items { 
      self.ref.child("users/" + userID + "/items/" + itemID).child(item.key).setValue(item.value) 
     } 
    } 

    ////////// 
    // Picker Controllers 

    //Arrays for picker views 
    let stateArray = ["State", "AL", "AK", "AZ", "AR", "CA", "CO", "CT", "DE", "FL", "GA", "HI", "ID", "IL", "IN", "IA", "KS", "KY", "LA", "ME", "MD", "MA", "MI", "MN", "MS", "MO", "MT", "NE", "NV", "NH", "NJ", "NM", "NY", "NC", "ND", "OH", "OK", "OR", "PA", "RI", "SC", "SD", "TN", "TX", "UT", "VT", "VA", "WA", "WV", "WI", "WY"] 
    var yearArray : [String] = [] 
    let errorArray = ["unable to load"] 

    let yearPickerView = UIPickerView() 
    let statePickerView = UIPickerView() 

    func setUpPickers() { 
     print("running setUpPickers") 
     // new picker 
     yearPickerView.delegate = self 
     yearTextField.inputView = yearPickerView 
     statePickerView.delegate = self 
     stateTextField.inputView = statePickerView 

     var i = 1900 
     let date = Date() 
     let calendar = Calendar.current 
     let maxYear = calendar.component(.year, from: date) 
     while i < (maxYear + 1) { 
      yearArray.insert(String(describing: i), at: 0) 
      i += 1 
     } 
    } 

    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { 
     print("setting titleForRow...") 
     if pickerView == statePickerView { 
      return stateArray[row] 
     } else if pickerView == yearPickerView { 
      return yearArray[row] 
     } else { 
      return errorArray[0] 
     } 
    } 

    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { 
     print("setting numberOfRowsInComponent...") 
     if pickerView == statePickerView { 
      return stateArray.count 
     } else if pickerView == yearPickerView { 
      return yearArray.count 
     } else { 
      return errorArray.count 
     } 
    } 

    public func numberOfComponents(in pickerView: UIPickerView) -> Int{ 
     print("setting numberOfComponents...") 
     return 1 
    } 

    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { 
     print("setting didSelectRow...") 

     if pickerView == statePickerView { 
      print("setting text of stateTextField") 
      stateTextField.text = stateArray[row] 

      if stateTextField.text == stateArray[0] { 
       stateTextField.textColor = UIColor.lightGray 
      } else { 
       stateTextField.textColor = UIColor.black 
      } 
     } else if pickerView == yearPickerView { 
      print("setting text of yearTextField") 
      yearTextField.text = yearArray[row] 

      if yearTextField.text == stateArray[0] { 
       yearTextField.textColor = UIColor.lightGray 
      } else { 
       yearTextField.textColor = UIColor.black 
      } 
     } 
    } 

    // 
    ////////// 


    /////////////////////////////////////// 
    // shifting text fields (add listeners in viewDidLoad) 
    func keyboardWillShow(notification:NSNotification){ 
     print("running keyboardWillShow...") 
     //give room at the bottom of the scroll view, so it doesn't cover up anything the user needs to tap 
     var userInfo = notification.userInfo! 
     var keyboardFrame:CGRect = (userInfo[UIKeyboardFrameBeginUserInfoKey] as! NSValue).cgRectValue 
     keyboardFrame = self.view.convert(keyboardFrame, from: nil) 

     var contentInset:UIEdgeInsets = self.scrollView.contentInset 
     contentInset.bottom = (keyboardFrame.size.height + 60) 
     self.scrollView.contentInset = contentInset 
    } 

    func keyboardWillHide(notification:NSNotification){ 
     print("running keyboardWillHide...") 
     let contentInset:UIEdgeInsets = UIEdgeInsets.zero 
     self.scrollView.contentInset = contentInset 

     print("saving...") 
     save() 
     print("finished keyboardWillHide...") 
    } 
    // 
    /////////////////////////////////////// 
} 

有谁知道为什么会这样离奇functi情况正在发生以及如何解决它?

预先感谢您的任何想法

+0

如果你从第二个viewcontroller的deleteButtonPressed注释行performSegue(withIdentifier:“backToTableView”,sender:self),然后运行代码,看看是什么结果? – 3stud1ant3

+0

尝试为“backToTableView”编写perpareForSegue,然后使用此空间将所有传递给变量的变量重新设置为“”。然后看看你重新加载时是否仍然发布已删除的信息。 – DoesData

+0

@DoesData,谢谢你的建议;这是一个很好的想法。我曾尝试用'prepareForSegue'将变量设置回“”,但实际上这使得更多重复 – Rbar

回答

0

解决方案:

keyboardWillHide功能删除save()


推理

如果帮助他人,问题是keyboardWillHide方法调用save()。在保存意味着发布到固定键的情况下,这不是问题,事实上甚至可能非常方便,因为每次完成编辑字段时,键盘都会隐藏,并将您的数据保存到firebase。 但是,因为我们发布到唯一密钥(itemID)而不是每次都是相同的密钥,这会产生重复的调用来创建并保存到firebase的密钥。然后,使用表视图回到控制器上,然后加载刚刚保存到firebase的所有重复值。