子更新的崩溃表(indexPath超出范围错误,导致我的应用程序崩溃错误)



我很难更新应用程序中控制表的数组。我希望能够更改Firebase数据库中的子节点,并在用户端对其进行更新,而无需编写代码并发送更新。我需要能够更改他们的标记,并让它在索引不超出范围的情况下更新表。

这是我的类结构,为用户提供信息:

import UIKit
class User: NSObject {
var Name: String?
var Email: String?
var UID: String?
var Tag: String?

}

在我的控制器中,我有以下代码用Firebase的信息初始化表:

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。这是一个超出范围的错误,导致我的应用程序崩溃。我真的需要帮助,过去几周我一直在为此而挣扎。

编辑:我决定使用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)

}

然而,我可以将所有数据拉入快照,但当我尝试附加时,它返回零。我在任何一行代码中都得到了零的错误;append(用户名!(

我很想知道如何停止这种nil,并让我的观察者不断倾听我的数据库中的变化。

编辑2:

以下是我的变量:

var allUsersArray = [User]()
var macroUsersArray = [User]()
var microUsersArray = [User]()

这是我的ViewDidLoad:

override func viewDidLoad() {
super.viewDidLoad()

updateDataArray()

}

这是我更新的DataArray代码:

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 { $0.Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { $0.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: { $0.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: { $0.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: { $0.Tag == key }) {
self.macroUsersArray.remove(at: userIndex)
self.microUsersArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.microTableView.reloadData()
self.tableView.reloadData()

}
}
})
}

我得到的是Macro和Micro的空数组。我不知道我做错了什么。

编辑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
}
}

我现在可以附加数组,但它们不会填充我的表。我也可以在Firebase中更改用户的标签,而不会导致应用程序崩溃,但它不会观察到更改后的标签并将用户移动到另一个数组。所以我在这两件事上需要帮助。

这个答案需要对目标进行一些设置和重述

目标是拥有两个数组,用作两个的数据源tableViews。一个数组包含用户类型:宏,另一个数组包含用户类型:micro。

如果用户类型从宏更改为微(反之亦然(,则OP希望从一个表中删除用户并将其添加到另一个表。

概念上的答案是:在Firebase中的users节点中添加一个观察者,当用户发生更改时,查看它是否是type属性,如果是,则从一个表中删除并添加到另一个表。

有很多解决方案,但让我给出这个非常冗长的答案,它可以在代码和属性观测器中减少。

从三个数组开始,一个用于容纳所有用户,另一个用于存放宏和微用户。假设UserClass具有macromicro的字符串type属性

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 { $0.type == "macro" }
self.microArray = self.allUsersArray.filter { $0.type == "micro" }
self.observeChangeInUserProperty()
}

下面的代码向users数组添加了一个观察者,当用户的任何属性发生更改时,该观察者将通知应用程序,并在快照中显示该用户节点。

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: { $0.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: { $0.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: { $0.key == key }) {
self.macroArray.remove(at: userIndex)
self.microArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.microTable.reloadData()
self.mactoTable.reloadData()
}
}
})
}

如前所述,这是大量无关的代码,可以使用属性观测器进行精简,也可以为两个表或许多其他解决方案利用单个数组。

编辑

如果你想知道如何从Firebase中填充所有用户数组,你需要有一个从快照中初始化的User类,下面是代码

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)
}
})
}

最新更新