功能触发先前打开的VC
问题描述:
我有一个表格视图。当我点击一个单元格时,它会将我带到一个页面,在该页面中我可以编辑数据并传递单元格中的所有信息。然后我可以点击“保存”/“删除”,并将更改发布到/从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情况正在发生以及如何解决它?
预先感谢您的任何想法
答
解决方案:
从keyboardWillHide
功能删除save()
推理
如果帮助他人,问题是keyboardWillHide
方法调用save()
。在保存意味着发布到固定键的情况下,这不是问题,事实上甚至可能非常方便,因为每次完成编辑字段时,键盘都会隐藏,并将您的数据保存到firebase。 但是,因为我们发布到唯一密钥(itemID
)而不是每次都是相同的密钥,这会产生重复的调用来创建并保存到firebase的密钥。然后,使用表视图回到控制器上,然后加载刚刚保存到firebase的所有重复值。
如果你从第二个viewcontroller的deleteButtonPressed注释行performSegue(withIdentifier:“backToTableView”,sender:self),然后运行代码,看看是什么结果? – 3stud1ant3
尝试为“backToTableView”编写perpareForSegue,然后使用此空间将所有传递给变量的变量重新设置为“”。然后看看你重新加载时是否仍然发布已删除的信息。 – DoesData
@DoesData,谢谢你的建议;这是一个很好的想法。我曾尝试用'prepareForSegue'将变量设置回“”,但实际上这使得更多重复 – Rbar