如何跟踪已处理的用户?

时间:2019-06-20 18:45:26

标签: ios swift dictionary

我有这个字典:

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,因为在下一个循环中容器为空。

2 个答案:

答案 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()
    })
}