我有这个字典:
var userDict : [String : Bool] = ["": true]
我要使用哪个位置,以便可以快速有效地检查用户是否已被处理。问题是我无法为其添加值。在网上找到的热门答案中,我已经做了以下工作。我该如何解决?
var processedUsers = Set<String>()
func search() {
for u in snapChildren {
print(u, " this is one of the users")
let uid = self.getUID(snapshot: u)
print(" Is \(uid) in processedUsers?", processedUsers.contains(uid), " This is the entiere thing: ", processedUsers)
if !processedUsers.contains(uid) {
print("hfsghfdsagfkdsafjlksadfhjklasdfhlksahfjklsadfhakd")
let user = User(theuserID: uid)
self.retrieveUsersInfo(userObj: user, completion: {
self.peopleArray.append(user)
self.processedUsers.insert(user.userID!)
self.tableView.reloadData()
})
}
要明确。我想添加诸如["HDSFG2323BFYDSG54": true]
我包括了更多的上下文代码。我有一个循环遍历用户的循环。在内部,我需要确定用户是否已被处理。
从打印语句中,我发现尽管得到了uid不在容器中的许多循环,但似乎没有添加uid,因为在下一个循环中容器为空。
答案 0 :(得分:1)
您的代码或多或少是正确的。这是在操场上运行的简化形式,您可以在其中看到您的逻辑有效。正如@vadian指出的那样,您不是“附加”到字典,而是为属性分配值,但是正如vdmzz指出的那样,您应该并且可以使用Set
来做到这一点。
import UIKit
struct User {
var uid: String
}
var processedUsers: Set<String> = Set()
var uids = ["HDSFG2323BGYDSG53", "JDSFG2323BPTDSG59", "ODSFG2323BABDSG50"]
uids.forEach({
if !processedUsers.contains($0) {
let user = User(uid: $0)
processedUsers.insert(user.uid)
print(processedUsers)
}
})
打印:
["HDSFG2323BGYDSG53"]
["HDSFG2323BGYDSG53", "JDSFG2323BPTDSG59"]
["HDSFG2323BGYDSG53", "ODSFG2323BABDSG50", "JDSFG2323BPTDSG59"]
但是,我高度怀疑您的代码仍无法正常工作的原因是由于retrieveUsersInfo
的异步特性。您正在遍历整个Set
处于空状态,并在用户获取 之后填充该值。这是我认为正在发生的事情的证明:
import UIKit
import PlaygroundSupport
struct User {
var uid: String
}
func retrieveUsersInfo(uid: String, completion: @escaping (User) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
let user = User(uid: uid)
completion(user)
}
}
var processedUsers: Set<String> = Set()
var uids = ["HDSFG2323BGYDSG53", "JDSFG2323BPTDSG59", "ODSFG2323BABDSG50"]
uids.forEach({
if !processedUsers.contains($0) {
retrieveUsersInfo(uid: $0, completion: { (user) in
processedUsers.insert(user.uid)
print("Callback returned", processedUsers)
})
print("Loop ended", processedUsers)
}
})
PlaygroundPage.current.needsIndefiniteExecution = true
输出:
Loop ended []
Loop ended []
Loop ended []
Callback returned ["HDSFG2323BGYDSG53"]
Callback returned ["HDSFG2323BGYDSG53", "JDSFG2323BPTDSG59"]
Callback returned ["HDSFG2323BGYDSG53", "JDSFG2323BPTDSG59", "ODSFG2323BABDSG50"]
因此,您的Set在循环结束时将始终为空,因为异步任务尚未返回。如果您要保留已处理过的uid的永久记录(NSUserDefaults,CoreData),这可能是好的,但是如果这是短暂的-意味着它将在应用程序关闭时消失,您将需要增强处理日志带有“状态”之类的东西(但是有很多方法可以解决这个问题)。
以下是实现Hashable
状态的示例:
import UIKit
import PlaygroundSupport
struct User {
var uid: String
var state: ProcessedState
init(uid: String) {
self.uid = uid
self.state = .none
}
enum ProcessedState {
case none
case started
case success
case error
}
}
extension User: Equatable {
static func == (lhs: User, rhs: User) -> Bool {
return lhs.uid == rhs.uid
}
}
extension User: Hashable {
var hashValue: Int {
return uid.hashValue
}
}
func retrieveUsersInfo(user: User, completion: @escaping (User) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
var user = user
user.state = .success // or .error
completion(user)
}
}
var processedUsers: Set<User> = Set()
var users: [User] = [
User(uid: "HDSFG2323BGYDSG53"),
User(uid: "JDSFG2323BPTDSG59"),
User(uid: "ODSFG2323BABDSG50")]
users.forEach({ user in
if processedUsers.first(where: { $0 == user })?.state != .success {
var user = user
user.state = .started
processedUsers.insert(user)
retrieveUsersInfo(user: user, completion: { (user) in
print("Callback returned", processedUsers)
})
print("Loop ended", processedUsers)
}
})
PlaygroundPage.current.needsIndefiniteExecution = true
答案 1 :(得分:1)
如果您要实现的唯一目标是跟踪已处理的用户,则可以改用 Set
var processedUsers = Set<String>()
...
processedUsers.insert(freshlyProcessedUsersUid) // insert
processedUsers.contains(uid) //checking if already has been processed
所以您的代码可能类似于:
if !processedUsers.contains(uid) {
let user = User(theuserID: uid)
self.retrieveUsersInfo(userObj: user, completion: {
self.peopleArray.append(user)
self.processedUsers.insert(user.uid)
self.tableView.reloadData()
})
}