使用Firebase和Swift从多个表格部分保存数据

时间:2018-01-10 15:36:01

标签: ios uitableview firebase firebase-realtime-database

这个问题可能非常广泛,但我找不到任何类似的方法。我有一个tableView,包含几个部分。它就像一个个人资料页面,用户可以在其中编辑他们的生物,即姓名,出生日期,性别等。生物被分成不同的部分。当我在tableViewController而不是tableViewCell中点击时,如何一次性保存所有数据。

我曾经常常将TableViewController中的数据发送到TableViewCell来填充单元格。但我现在需要相反的操作,其中TableViewCell的数据被发送回TableViewController,以便我定义要保存到数据库的内容。

以下是我将如何保存在普通ViewController中的示例:

func saveData() {

    guard let firstNameText = firstNameField.text, let lastNameText = lastNameField.text else { return }

    guard let uid = Auth.auth().currentUser else { return }

    let databseRef = Database.database().reference(withPath: "users/\(uid)")

    let bioItem: [String : Any] = ["firstName" : firstNameText, "lastName" : lastNameText]

    databseRef.updateChildValues(bioItem)

} 

更新

以下是我尝试使用以下建议的解决方案:

protocol TextFieldCellDelegate: class {
    func textFieldCell(_ cell: FirstNameCell, didChangeText text: String)
}

class FirstNameCell: UITableViewCell {

    weak var delegate: TextFieldCellDelegate?
    var indexPath: IndexPath!

    var user: User? {
        didSet {
            guard let user = user else { return }
            nameField.text = user.firstName
        }
    }

    lazy var nameField: UITextField = {
        let field = UITextField()
        return field
    }()

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupViews()

    }
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    override func setupViews() {
        addSubview(nameField)
        // Adding constraints...
    }

    @objc private func textFieldDidChange(_ textField: UITextField) {
        guard let text = nameField.text else {
            return
        }

        delegate?.textFieldCell(self, didChangeText: text)
    }

}

的ViewController:

var user: User!

func textFieldCell(_ cell: FirstNameCell, didChangeText text: String) {
    switch cell.indexPath.section {
    case 0:
        if cell.indexPath.row == 0 {
            user.firstName = text

            print("New name: \(text)")
        }
    // handle other rows
    default:
        break
        // handle other sections and rows
    }
}



func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    switch (indexPath.section) {
    case 0:

        let cell = tableView.dequeueReusableCell(withIdentifier: firstNameCell, for: indexPath) as! FirstNameCell
        cell.user = self.user
        cell.delegate = self //error
        cell.indexPath = indexPath
        return cell

    case 1:
        let cell = tableView.dequeueReusableCell(withIdentifier: secondNameCell, for: indexPath) as! SecondNameCell
        cell.user = self.user
        return cell
    default:
        break
    }
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
    return cell

}

1 个答案:

答案 0 :(得分:1)

可以找到示例项目on GitHub

我已经用几种不同的方式解决了这个问题。我认为最适合您的应用程序体系结构的方式如下,假设您编辑配置文件视图的示例如下:

创建一个可变用户struct并创建一个局部变量,每次编辑一个表行时都会对其进行编辑。

struct User {
    var firstName: String?
    var lastName: String?
    var birthday: Date?
}

然后在您的编辑个人资料视图控制器中:

var userModel = User()

创建单元格子类时,您需要按照此SO post中的说明注册操作UIControlEventEditingChanged,然后每次更改文本字段时通知代理该更改已发生,以便您的视图控制器可以接收更改事件

protocol TextFieldCellDelegate: class {
    func textFieldCell(_ cell: TextFieldCell, didChangeText text: String)
}

在单元子类中为委托创建变量并为indexPath创建变量:

weak var delegate: TextFieldCellDelegate?
var indexPath: IndexPath!

视图控制器将使用indexPath变量来确定正在修改哪个单元格。

最后在您之前连接的编辑更改操作中的单元格子类中:

@objc private func textFieldDidChange(_ textField: UITextField) {
    guard let text = textField.text else {
        return
    }

    delegate?.textFieldCell(self, didChangeText: text)
}

在视图控制器中将单元格的委托设置为行的单元格中的视图控制器并设置indexPath

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    //...

    cell.delegate = self
    cell.indexPath = indexPath

    //...
}

最后在视图控制器中符合TextFieldCellDelegate

func textFieldCell(_ cell: TextFieldCell, didChangeText text: String) {
    switch cell.indexPath.section {
    case TableSection.user.rawValue:
        if cell.indexPath.row == 0 {
            userModel.firstName = text
        }
        // handle other rows
    default:
        // handle other sections and rows
    }
}

现在,每次编辑表格中的行时,都会更新userModel。用户完成个人资料编辑后,点按保存按钮,然后调用saveData()功能检查userModel上的每个媒体资源,看看您需要保存的内容:

// ...

var bioItemToUpdate = [String : Any]()

if let firstName = userModel.firstName {
    bioItemToUpdate["firstName"] = firstName
}

if let lastName = userModel.lastName {
    bioItemToUpdate["lastName"] = lastName
}

if let birthday = userModel.birthday {
    bioItemToUpdate["birthday"] = birthday
}

databseRef.updateChildValues(bioItemToUpdate)

使用此方法还可以产生在启用保存按钮之前要求某些字段有效的好处。

我希望这有助于您为自己的应用找到一个好的解决方案!