wake-up-neo.com

Optionaler Verschluss und überprüfe, ob er null ist

Was ich also haben möchte, ist eine Klasse, der möglicherweise ein Abschluss in einer Funktion übergeben wird, und die möglicherweise auch irgendwann diesen Abschluss ignorieren möchte. Wie kann ich überprüfen, ob die Verschlussvariable gesetzt ist und wie kann ich sie löschen, wenn ich damit fertig bin?

'! =' Kann nicht mit einer Argumentliste vom Typ '(@lvalue (sucsess: Bool !, products: [AnyObject]!) -> () ?, NilLiteralConvertible)' Type '(sucsess: Bool !, products: [AnyObject ]!) -> ()? ' entspricht nicht dem Protokoll '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

Sie müssen Ihre Abschlussunterschrift in Klammern setzen, damit der Abschluss selbst optional ist. So wie es jetzt geschrieben ist, gibt der Abschluss ein optionales Void (was eigentlich keinen Sinn ergibt) zurück.

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

Einige Stilpunkte und Überarbeitungen Ihres Beispielcodes:

 // 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

Zunächst müssen Sie in Ihrer Deklaration des Completion-Handlers das Ganze mit runden Klammern als optional deklarieren:

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

Oder vielleicht besser, Sie können das letzte () Durch Void ersetzen:

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

Beachten Sie auch, ich glaube nicht, dass Sie das Bool optional machen wollten (denn wenn der Abschluss existiert, übergeben Sie vermutlich immer einen success-Wert von true oder false). Das Array von items kann natürlich optional sein.

Wenn Sie fertig sind, müssen Sie nur das Optionale auspacken:

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

Dies führt den Abschluss genau dann durch, wenn es nicht nil ist, und vermeidet die Notwendigkeit, explizit zu prüfen, ob es nil war.


Für das, was es wert ist, könnte dies ein Fall sein, in dem Ihr typealias dies weniger verwirrend macht:

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

Dann ist die Eigenschaft einfach:

var completionHandler: CompletionHandlerClosureType?

Die Funktion, die dieses completionHandler als optionalen Parameter verwendet, kann Folgendes ausführen:

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

und dann ist die endgültige Vervollständigungslogik unverändert:

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

(Beachten Sie, dass das oben Genannte für Swift 3. Bitte lesen Sie vorherige Überarbeitung dieser Antwort, wenn Sie Swift sehen möchten 2 Wiedergaben.)

42
Rob