web-dev-qa-db-ja.com

オプションのクロージャとそれがnilであるかどうかをチェック

だから、私が欲しいのは、関数で渡されたクロージャーを取得できるクラスであり、ある時点でそのクロージャーを無視したい場合もあります。クロージャー変数が設定されているかどうかを確認するにはどうすればよいですか?完了したら削除できますか?

タイプの引数リストで「!=」を呼び出すことはできません(@lvalue(成功:Bool !,製品:[AnyObject]!)->()?, NilLiteralConvertible) 'タイプ'(成功:Bool !,製品:[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'
        }
    }
}
43

クロージャー自体をオプションにするために、クロージャーシグネチャを括弧で囲む必要があります。現在の記述方法では、クロージャーはオプションの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
    }
}
45
Nate Cook

最初に、完了ハンドラーの宣言では、括弧を使用してオプション全体を宣言する必要があります。

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

または、おそらくより良い方法として、最後の()Voidに置き換えることができます。

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

また、Boolをオプションにするつもりはないことに注意してください(クロージャーが存在する場合は、常にsuccess値またはtrueまたはfalse)。明らかに、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レンディション。)

42
Rob