web-dev-qa-db-fra.com

fermeture facultative et vérifier si elle est nulle

Donc, ce que je veux, c'est une classe qui peut obtenir une fermeture qui lui est transmise dans une fonction, elle peut aussi à un moment donné vouloir ignorer cette fermeture. Comment puis-je vérifier si la variable de fermeture est définie et comment puis-je la supprimer lorsque j'en ai fini avec elle?

Impossible d'appeler '! =' Avec une liste d'arguments de type '(@lvalue (sucsess: Bool !, products: [AnyObject]!) -> ()?, NilLiteralConvertible)' Type '(sucsess: Bool !, products: [AnyObject ]!) -> ()? ' n'est pas conforme au protocole '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'
        }
    }
}
43
Ágúst Rafnsson

Vous devez mettre votre signature de fermeture entre parenthèses pour rendre la fermeture elle-même facultative. De la façon dont il est écrit maintenant, la fermeture retourne un Void (qui n'a pas vraiment de sens).

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

Quelques points de style et révisions de votre exemple de code:

 // 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
    }
}
45
Nate Cook

Tout d'abord, dans votre déclaration du gestionnaire d'achèvement, vous devez déclarer le tout comme facultatif avec l'utilisation de parenthèses:

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

Ou, peut-être mieux, vous pouvez remplacer cette dernière () avec Void:

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

Notez également que je ne pense pas que vous vouliez rendre le Bool facultatif (car si la fermeture existe, vous passez probablement toujours une valeur de success de true ou false). De toute évidence, le tableau de items pourrait bien être facultatif.

Quoi qu'il en soit, une fois terminé, vous devez simplement vous assurer de déballer cette option:

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

Ceci effectue la fermeture si et seulement si ce n'est pas nil, évitant ainsi de vérifier explicitement si c'était nil.


Pour ce que ça vaut, cela pourrait être un cas où votre typealias pourrait rendre cela moins déroutant:

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

La propriété est alors simplement:

var completionHandler: CompletionHandlerClosureType?

La fonction qui prend ce completionHandler comme paramètre facultatif pourrait faire:

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

puis la logique d'achèvement finale est inchangée:

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

(Remarque, ce qui précède a été modifié pour Swift 3. Veuillez voir révision précédente de cette réponse si vous voulez voir Swift 2 rendus.)

42
Rob