子更新崩溃 table(indexPath 超出范围错误导致我的应用程序崩溃错误)
Child Updated crashing table (indexPath is out of range error that crashes my app Error)
我很难更新我的应用程序中控制 table 的数组。我希望能够更改 Firebase 数据库中的子节点,并在我的用户端更新它,而无需编写代码和发送更新。我需要能够更改他们的标签并让它更新 table 而索引不超出范围。
这是我的 Class 用户信息结构:
import UIKit
class User: NSObject {
var Name: String?
var Email: String?
var UID: String?
var Tag: String?
}
在我的控制器中,我有以下代码使用来自 Firebase 的信息初始化 table:
func CreateDataArray() {
Database.database().reference().child("Users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.UID = dictionary["UID"] as? String
user.Tag = dictionary["Tag"] as? String
if user.Tag == "Macro" {
self.macroUsersArray.append(user)
} else if user.Tag == "Micro" {
self.microUsersArray.append(user)
}
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
print(dictionary)
print(self.macroUsersArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
然后我有一个函数可以侦听来自我的 Firebase 的任何更改并更新数组:
func updateDataArray() {
Database.database().reference().child("Users").observe(.childChanged, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.UID = dictionary["UID"] as? String
user.Tag = dictionary["Tag"] as? String
if user.Tag == "Macro" {
self.microUsersArray.remove(at: 2)
} else if user.Tag == "Micro" {
self.macroUsersArray.remove(at: 2)
}
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
print(dictionary)
print(self.macroUsersArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
我想让原来拥有标签“宏”的用户切换到“微”,从宏列表中删除并显示在微列表中。我无法让数组追加并继续获取 indexPath is out of range 错误,导致我的应用程序崩溃。我真的需要帮助,过去几周一直在为此苦苦挣扎。
编辑:我决定使用 observe.value 以便在我进行更改时它会读取它。这是我创建用户信息的代码:
func CreateDataArray() {
Database.database().reference().child("Users").observe(.value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.Tag = dictionary["Tag"] as? String
if user.Tag == "Macro" {
self.macroUsersArray.append(user)
} else if user.Tag == "Micro" {
self.microUsersArray.append(user)
}
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
print(dictionary)
print(self.macroUsersArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
但是,我能够将所有数据提取到快照中,但是当我尝试追加时它返回 nil。我在带有“append(User.Name!)
的任何代码行上都收到 nil 错误
我很想知道如何停止这个 nil 并允许我的观察者继续监听我的数据库中的变化。
编辑 2:
这是我的变量:
var allUsersArray = [User]()
var macroUsersArray = [User]()
var microUsersArray = [User]()
这是我的 ViewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
updateDataArray()
}
这是我的 updateDataArray 代码:
func updateDataArray() {
Database.database().reference().child("Users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.UID = dictionary["UID"] as? String
user.Tag = dictionary["Tag"] as? String
self.allUsersArray.append(user)
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
self.macroUsersArray = self.allUsersArray.filter { [=17=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=17=].Tag == "Micro" }
self.observeChangeInUserProperty()
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
这是 observeChangeInUserProperty() 函数:
func observeChangeInUserProperty() {
let ref = Database.database().reference().child("Users").child("Talent")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let tag = snapshot.childSnapshot(forPath: "Tag").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { [=18=].Tag == key }) {
if user.Tag != tag { //if the tag changed, handle it
user.Tag = tag //update the allUsersArray
if tag == "Macro" { //if the new tag is Macro remove the user from the Micro array
if let userIndex = self.microUsersArray.firstIndex(where: { [=18=].Tag == key }) {
self.microUsersArray.remove(at: userIndex)
self.macroUsersArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroUsersArray.firstIndex(where: { [=18=].Tag == key }) {
self.macroUsersArray.remove(at: userIndex)
self.microUsersArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.microTableView.reloadData()
self.tableView.reloadData()
}
}
})
}
我得到的是宏和微的空数组。我不知道我做错了什么。
编辑 3:
这是我从 Firebase 初始化的新用户结构:
import UIKit
import Firebase
class User: NSObject {
var Name: String?
var Email: String?
var UID: String?
var Tag: String?
init?(from snapshot: DataSnapshot) {
let dictionary = snapshot.value as? [String: Any]
self.Name = dictionary!["Name"] as? String
self.Email = dictionary!["Email"] as? String
self.UID = dictionary!["UID"] as? String
self.Tag = dictionary!["Tag"] as? String
}
}
我现在可以附加数组,但它们没有填充我的 table。我还可以在 Firebase 中更改用户的标签,而不会导致应用程序崩溃,但它不会观察到更改后的标签并将用户移动到另一个数组。所以我需要这两件事的帮助。
这个答案需要一些设置和重述目标
The goal is to have two arrays, used as dataSources for two
tableViews. One array contains user type: macro and the other array
contains user type: micro.
If a user type is changed from macro to micro (and vice-versa) the OP
wants to remove the user from one table and add it to the other.
概念上的答案是:在 Firebase 中向用户节点添加一个观察者,当用户发生变化时,查看它是否属于 属性 类型,如果是,则从 table 中移除并将其添加到另一个。
有很多解决方案,但让我提出这个非常冗长的答案,可以减少代码和 属性 观察者。
从三个数组开始,一个包含所有用户,另一个包含宏用户和微用户。假设 UserClass 有一个字符串 type
属性 macro
或 micro
var allUsersArray = [UserClass]()
var macroArray = [UserClass]()
var microArray = [UserClass]()
读入所有用户,然后从中将用户划分为各自的类型
...read firebase single event of .value, with: { snapshot in
and populate allUsersArray from the snapshot..
self.macroArray = self.allUsersArray.filter { [=11=].type == "macro" }
self.microArray = self.allUsersArray.filter { [=11=].type == "micro" }
self.observeChangeInUserProperty()
}
下面的代码将一个观察者添加到用户数组,当任何 属性 用户更改时通知应用程序,并在快照中显示该用户节点。
func observeChangeInUserProperty() {
let ref = self.ref.child("users")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let type = snapshot.childSnapshot(forPath: "type").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { [=12=].key == key }) {
if user.type != type { //if the type changed, handle it
user.type = type //update the allUsersArray
if type == "macro" { //if the new type is macro remove the user from the micro array
if let userIndex = self.microArray.firstIndex(where: { [=12=].key == key }) {
self.microArray.remove(at: userIndex)
self.macroArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroArray.firstIndex(where: { [=12=].key == key }) {
self.macroArray.remove(at: userIndex)
self.microArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.microTable.reloadData()
self.mactoTable.reloadData()
}
}
})
}
如前所述,这是很多无关代码,可以使用 属性 观察者进行压缩,或者为 table 或许多其他解决方案利用单个数组。
编辑
如果您想知道如何从 Firebase 填充所有用户数组,您需要有一个从快照初始化的用户 class,代码如下
func loadAllUsersAndPopulateArray() {
let ref = self.ref.child("users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = UserClass(withSnap: userSnap)
self.allUsersArray.append(user)
}
})
}
我很难更新我的应用程序中控制 table 的数组。我希望能够更改 Firebase 数据库中的子节点,并在我的用户端更新它,而无需编写代码和发送更新。我需要能够更改他们的标签并让它更新 table 而索引不超出范围。
这是我的 Class 用户信息结构:
import UIKit
class User: NSObject {
var Name: String?
var Email: String?
var UID: String?
var Tag: String?
}
在我的控制器中,我有以下代码使用来自 Firebase 的信息初始化 table:
func CreateDataArray() {
Database.database().reference().child("Users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.UID = dictionary["UID"] as? String
user.Tag = dictionary["Tag"] as? String
if user.Tag == "Macro" {
self.macroUsersArray.append(user)
} else if user.Tag == "Micro" {
self.microUsersArray.append(user)
}
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
print(dictionary)
print(self.macroUsersArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
然后我有一个函数可以侦听来自我的 Firebase 的任何更改并更新数组:
func updateDataArray() {
Database.database().reference().child("Users").observe(.childChanged, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.UID = dictionary["UID"] as? String
user.Tag = dictionary["Tag"] as? String
if user.Tag == "Macro" {
self.microUsersArray.remove(at: 2)
} else if user.Tag == "Micro" {
self.macroUsersArray.remove(at: 2)
}
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
print(dictionary)
print(self.macroUsersArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
我想让原来拥有标签“宏”的用户切换到“微”,从宏列表中删除并显示在微列表中。我无法让数组追加并继续获取 indexPath is out of range 错误,导致我的应用程序崩溃。我真的需要帮助,过去几周一直在为此苦苦挣扎。
编辑:我决定使用 observe.value 以便在我进行更改时它会读取它。这是我创建用户信息的代码:
func CreateDataArray() {
Database.database().reference().child("Users").observe(.value, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.Tag = dictionary["Tag"] as? String
if user.Tag == "Macro" {
self.macroUsersArray.append(user)
} else if user.Tag == "Micro" {
self.microUsersArray.append(user)
}
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
print(dictionary)
print(self.macroUsersArray)
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
但是,我能够将所有数据提取到快照中,但是当我尝试追加时它返回 nil。我在带有“append(User.Name!)
的任何代码行上都收到 nil 错误我很想知道如何停止这个 nil 并允许我的观察者继续监听我的数据库中的变化。
编辑 2:
这是我的变量:
var allUsersArray = [User]()
var macroUsersArray = [User]()
var microUsersArray = [User]()
这是我的 ViewDidLoad:
override func viewDidLoad() {
super.viewDidLoad()
updateDataArray()
}
这是我的 updateDataArray 代码:
func updateDataArray() {
Database.database().reference().child("Users").observe(.childAdded, with: { (snapshot) in
if let dictionary = snapshot.value as? [String: AnyObject] {
let user = User()
//self.setValuesForKeys(dictionary)
user.Name = dictionary["Name"] as? String
user.Email = dictionary["Email"] as? String
user.UID = dictionary["UID"] as? String
user.Tag = dictionary["Tag"] as? String
self.allUsersArray.append(user)
self.users.append(user)
self.userName.append(user.Name!)
self.filteredNames.append(user.Name!)
self.macroUsersArray = self.allUsersArray.filter { [=17=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=17=].Tag == "Micro" }
self.observeChangeInUserProperty()
DispatchQueue.main.async {
self.tableView.reloadData()
}
}
}, withCancel: nil)
}
这是 observeChangeInUserProperty() 函数:
func observeChangeInUserProperty() {
let ref = Database.database().reference().child("Users").child("Talent")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let tag = snapshot.childSnapshot(forPath: "Tag").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { [=18=].Tag == key }) {
if user.Tag != tag { //if the tag changed, handle it
user.Tag = tag //update the allUsersArray
if tag == "Macro" { //if the new tag is Macro remove the user from the Micro array
if let userIndex = self.microUsersArray.firstIndex(where: { [=18=].Tag == key }) {
self.microUsersArray.remove(at: userIndex)
self.macroUsersArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroUsersArray.firstIndex(where: { [=18=].Tag == key }) {
self.macroUsersArray.remove(at: userIndex)
self.microUsersArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.microTableView.reloadData()
self.tableView.reloadData()
}
}
})
}
我得到的是宏和微的空数组。我不知道我做错了什么。
编辑 3:
这是我从 Firebase 初始化的新用户结构:
import UIKit
import Firebase
class User: NSObject {
var Name: String?
var Email: String?
var UID: String?
var Tag: String?
init?(from snapshot: DataSnapshot) {
let dictionary = snapshot.value as? [String: Any]
self.Name = dictionary!["Name"] as? String
self.Email = dictionary!["Email"] as? String
self.UID = dictionary!["UID"] as? String
self.Tag = dictionary!["Tag"] as? String
}
}
我现在可以附加数组,但它们没有填充我的 table。我还可以在 Firebase 中更改用户的标签,而不会导致应用程序崩溃,但它不会观察到更改后的标签并将用户移动到另一个数组。所以我需要这两件事的帮助。
这个答案需要一些设置和重述目标
The goal is to have two arrays, used as dataSources for two tableViews. One array contains user type: macro and the other array contains user type: micro.
If a user type is changed from macro to micro (and vice-versa) the OP wants to remove the user from one table and add it to the other.
概念上的答案是:在 Firebase 中向用户节点添加一个观察者,当用户发生变化时,查看它是否属于 属性 类型,如果是,则从 table 中移除并将其添加到另一个。
有很多解决方案,但让我提出这个非常冗长的答案,可以减少代码和 属性 观察者。
从三个数组开始,一个包含所有用户,另一个包含宏用户和微用户。假设 UserClass 有一个字符串 type
属性 macro
或 micro
var allUsersArray = [UserClass]()
var macroArray = [UserClass]()
var microArray = [UserClass]()
读入所有用户,然后从中将用户划分为各自的类型
...read firebase single event of .value, with: { snapshot in
and populate allUsersArray from the snapshot..
self.macroArray = self.allUsersArray.filter { [=11=].type == "macro" }
self.microArray = self.allUsersArray.filter { [=11=].type == "micro" }
self.observeChangeInUserProperty()
}
下面的代码将一个观察者添加到用户数组,当任何 属性 用户更改时通知应用程序,并在快照中显示该用户节点。
func observeChangeInUserProperty() {
let ref = self.ref.child("users")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let type = snapshot.childSnapshot(forPath: "type").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { [=12=].key == key }) {
if user.type != type { //if the type changed, handle it
user.type = type //update the allUsersArray
if type == "macro" { //if the new type is macro remove the user from the micro array
if let userIndex = self.microArray.firstIndex(where: { [=12=].key == key }) {
self.microArray.remove(at: userIndex)
self.macroArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroArray.firstIndex(where: { [=12=].key == key }) {
self.macroArray.remove(at: userIndex)
self.microArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.microTable.reloadData()
self.mactoTable.reloadData()
}
}
})
}
如前所述,这是很多无关代码,可以使用 属性 观察者进行压缩,或者为 table 或许多其他解决方案利用单个数组。
编辑
如果您想知道如何从 Firebase 填充所有用户数组,您需要有一个从快照初始化的用户 class,代码如下
func loadAllUsersAndPopulateArray() {
let ref = self.ref.child("users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = UserClass(withSnap: userSnap)
self.allUsersArray.append(user)
}
})
}