Swift可以从异步Void返回块中返回值吗?

时间:2022-09-10 23:52:25

I want to create a function to check if user_id is already in my database.

我想创建一个函数来检查user_id是否已经在我的数据库中。

class func checkIfUserExsits(uid:String) -> Bool {
    userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value, withBlock: { (snapShot: FDataSnapshot!) -> Void in
                if snapShot.value is NSNull {
                    return false
                } else {
                    return true
                }
    })
}

However, observeSingleEventOfType is a API provided by 3rd party Firebase. It is defined to return Void.

但是,observeSingleEventOfType是第三方Firebase提供的API。它定义为返回Void。

  • (void)observeSingleEventOfType:(FEventType)eventType withBlock:(void ( ^ ) ( FDataSnapshot *snapshot ))block
  • (void)observeSingleEventOfType:(FEventType)eventType withBlock:(void(^)(FDataSnapshot * snapshot))block

Error: Type 'Void' does not conform to protocol 'BooleanLiteralConvertible'

错误:类型'Void'不符合协议'BooleanLiteralConvertible'

Appreciate any kind of helps.

感谢任何帮助。


UPDATE

UPDATE

I am trying a different way:

我正在尝试另一种方式:

class func checkIfExist(uid: String) -> Bool {
    var answer:Bool = false
    var text:String = "not yet completed"
    let queue = dispatch_group_create()
    dispatch_group_enter(queue)
        userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value, withBlock: { (snapShot: FDataSnapshot!) -> Void in
                if snapShot.value is NSNull {
                    text = "This is a new user"
                    answer  = false
                    dispatch_group_leave(queue)
                } else {
                    text = "Found the user in Firebase"
                    answer = true
                    dispatch_group_leave(queue)
                }
        })
    dispatch_group_wait(queue, DISPATCH_TIME_FOREVER)
    println(text)
    return answer
}

Somehow it just freeze there. I know this approach could be off-topic now. But please help.

不知怎的,它只是冻结在那里。我知道这种方法现在可能是偏离主题的。但请帮忙。

1 个解决方案

#1


14  

You should employ asynchronous completion handler yourself:

您应该自己使用异步完成处理程序:

class func checkIfUserExists(uid: String, completionHandler: (Bool) -> ()) {
    userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value) { snapShot in
        if snapShot.value is NSNull {
            completionHandler(false)
        } else {
            completionHandler(true)
        }
    }
}

You can then call this like so:

然后您可以这样调用:

MyClass.checkIfUserExists(uid) { success in
    // use success here
}

// but not here

In your revised question, you demonstrate the use of dispatch groups to make this asynchronous method behave synchronously. (Semaphores are also often used to the same ends.)

在修订后的问题中,您演示了使用调度组来使此异步方法同步运行。 (信号量通常也用于相同的目的。)

Two issues:

两个问题:

  1. This will deadlock if they dispatch their completion handler back to the main queue (and in many cases, libraries will do this to simplify life for us), because you're coincidentally blocking the very same thread they're trying to use. I don't know if that's what they've done here, but is likely.

    如果他们将完成处理程序发送回主队列(在很多情况下,库会这样做以简化我们的生活),这将会死锁,因为你巧合地阻止了他们试图使用的同一个线程。我不知道他们在这里做了什么,但很可能。

    If you want to confirm this, temporarily remove dispatch group and then examine NSThread.isMainThread and see if it's running in main thread or not.

    如果要确认这一点,请暂时删除调度组,然后检查NSThread.isMainThread并查看它是否在主线程中运行。

  2. You never should block the main thread, anyway. They provided an asynchronous interface for good reason, so you should use asynchronous patterns when calling it. Don't fight the asynchronous patterns, but rather embrace them.

    无论如何,你永远不应该阻止主线程。他们提供了一个异步接口是有充分理由的,因此在调用它时应该使用异步模式。不要对抗异步模式,而是接受它们。

#1


14  

You should employ asynchronous completion handler yourself:

您应该自己使用异步完成处理程序:

class func checkIfUserExists(uid: String, completionHandler: (Bool) -> ()) {
    userRef.childByAppendingPath(uid).observeSingleEventOfType(.Value) { snapShot in
        if snapShot.value is NSNull {
            completionHandler(false)
        } else {
            completionHandler(true)
        }
    }
}

You can then call this like so:

然后您可以这样调用:

MyClass.checkIfUserExists(uid) { success in
    // use success here
}

// but not here

In your revised question, you demonstrate the use of dispatch groups to make this asynchronous method behave synchronously. (Semaphores are also often used to the same ends.)

在修订后的问题中,您演示了使用调度组来使此异步方法同步运行。 (信号量通常也用于相同的目的。)

Two issues:

两个问题:

  1. This will deadlock if they dispatch their completion handler back to the main queue (and in many cases, libraries will do this to simplify life for us), because you're coincidentally blocking the very same thread they're trying to use. I don't know if that's what they've done here, but is likely.

    如果他们将完成处理程序发送回主队列(在很多情况下,库会这样做以简化我们的生活),这将会死锁,因为你巧合地阻止了他们试图使用的同一个线程。我不知道他们在这里做了什么,但很可能。

    If you want to confirm this, temporarily remove dispatch group and then examine NSThread.isMainThread and see if it's running in main thread or not.

    如果要确认这一点,请暂时删除调度组,然后检查NSThread.isMainThread并查看它是否在主线程中运行。

  2. You never should block the main thread, anyway. They provided an asynchronous interface for good reason, so you should use asynchronous patterns when calling it. Don't fight the asynchronous patterns, but rather embrace them.

    无论如何,你永远不应该阻止主线程。他们提供了一个异步接口是有充分理由的,因此在调用它时应该使用异步模式。不要对抗异步模式,而是接受它们。