可选关闭并检查它是不是为 nil

Posted

技术标签:

【中文标题】可选关闭并检查它是不是为 nil【英文标题】:optional closure and check if it is nil可选关闭并检查它是否为 nil 【发布时间】:2014-11-25 12:41:39 【问题描述】:

所以我想要的是一个可以在函数中将闭包传递给它的类,它也可能在某些时候想要忽略该闭包。如何检查闭包变量是否已设置,完成后如何将其删除?

不能使用类型为 '(@lvalue (succsess: Bool!, products: [AnyObject]!) -> ()?, NilLiteralConvertible)' 类型 '(成功:布尔!,产品:[AnyObject]!)->()?不符合 协议'NilLiteralConvertible'

class someClass
    //typealias completionHandlerClosureType = (sucsess:Bool!, items:[AnyObject]!)->()
    var completionHandler:(sucsess:Bool!, items:[AnyObject]!)->()?
    var hitpoints = 100
    var someset = ["oh no!","avenge me!"]
    init()

    func getHitFunc(impact:Int, passedCompletionsHandler:(sucsess:Bool!, items:[AnyObject]!)->())
        completionHandler = passedCompletionsHandler
        hitpoints = hitpoints - impact
    

    func checkIfDead
        if hitpoints<=0                // The error received
            if completionHandler != nil// Cannot invoke '!=' with an argument list of type 
                                        //'(@lvalue (sucsess: Bool!, products: [AnyObject]!) -> ()?, NilLiteralConvertible)' 
                //run the handler if dead
                completionHandler(sucsess: true, items: someset)
                //do not run it again
                completionHandler = nil     //Type '(sucsess: Bool!, products: [AnyObject]!) -> ()?' does not conform to protocol 'NilLiteralConvertible'
            
        
        else
            completionHandler = nil      //Type '(sucsess: Bool!, products: [AnyObject]!) -> ()?' does not conform to protocol 'NilLiteralConvertible'
        
    

【问题讨论】:

【参考方案1】:

您需要将闭包签名包装在括号中,以使闭包本身是可选的。按照现在的写法,闭包返回一个可选的 Void(这实际上没有意义)。

var completionHandler: ((sucsess:Bool!, items:[AnyObject]!)->())?

您的示例代码的一些样式点和修订:

 // Capitalize class names so it's clear what's a class 
class SomeClass 
    // "success" has two "c"s
    var completionHandler: ((success:Bool!, items:[AnyObject]!)->())?
    var hitpoints = 100
    var someset = ["oh no!","avenge me!"]

    init()  

    func getHitFunc(impact:Int, passedCompletionsHandler:(success:Bool!, items:[AnyObject]!)->())
        completionHandler = passedCompletionsHandler
        hitpoints = hitpoints - impact
    

    // You were missing the argument list here:
    func checkIfDead() 
        if hitpoints <= 0 

            // Rather than checking to see if the completion handler exists, you can
            // just call it using optional syntax like this:
            completionHandler?(success: true, items: someset)
        
        completionHandler = nil
    

【讨论】:

【参考方案2】:

首先,在完成处理程序的声明中,您需要使用括号将整个内容声明为可选:

var completionHandler: ((_ success: Bool, _ items: [Any]?) -> ())?

或者,也许更好,您可以将最后的 () 替换为 Void

var completionHandler: ((_ success: Bool, _ items: [Any]?) -> Void)?

另外,请注意,我不认为您打算将 Bool 设为可选(因为如果存在闭包,您可能总是传递 truefalsesuccess 值)。显然,items 的数组很可能是可选的。

无论如何,完成后,您只需确保打开该可选选项:

func checkIfDead() 
    if hitpoints <= 0 
        completionHandler?(true, items)
    
    completionHandler = nil

当且仅当它不是nil 时才会执行闭包,避免需要显式检查它是否是nil


对于它的价值,这可能是您的typealias 可能会使这不那么混乱的情况:

typealias CompletionHandlerClosureType = (_ success: Bool, _ items: [Any]?) -> Void

那么属性就是:

var completionHandler: CompletionHandlerClosureType?

将此completionHandler 作为可选参数的函数可以这样做:

func startSomeProcess(passedCompletionHandler: CompletionHandlerClosureType?) 
    completionHandler = passedCompletionHandler
    // do whatever else you want

然后最后的完成逻辑不变:

func finishSomeProcess() 
    completionHandler?(true, items)
    completionHandler = nil


(请注意,以上内容已针对 Swift 3 进行了修改。如果您想查看 Swift 2 版本,请参阅此答案的 previous revision。)

【讨论】:

类型别名是很好的解决方案 这个解释太棒了。仍然适用于 Swift 4。完成块在 swift 中比 Objective-C 有了很大改进,但仍然需要一些努力才能使其正确,特别是当我移植过去的几个 Objective-C 类时,有人深思熟虑地忽略了多年在这个项目中。

以上是关于可选关闭并检查它是不是为 nil的主要内容,如果未能解决你的问题,请参考以下文章

在读取 JSON 时打开可选值时意外发现 nil [关闭]

检查环境变量是不是存在并设置为 True [关闭]

检查 nil 的非可选值

检查Core Data中是不是存在对象[关闭]

VBA DAO.Recordset 在尝试关闭它时为空或未设置 - 但我事先检查它是不是为空

我有一个可选值,它被分配了一个值,成功打印,但是当我检查它时它是 nil [重复]