Подтвердить что ты не робот

Опциональное закрытие и проверить, нет ли он

Так что я хочу иметь класс, который может получить закрытие, переданное ему в функции, он также может в какой-то момент хотеть игнорировать это закрытие. Как проверить, установлена ​​ли переменная закрытия и hwo можно удалить ее, когда я закончил с ней?

Невозможно вызвать '! =' с помощью списка аргументов типа (@lvalue (sucess: Bool!, products: [AnyObject]!) → ()?, NilLiteralConvertible) 'Тип '(sucsess: Bool!, products: [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'
        }
    }
}
4b9b3361

Ответ 1

Вам нужно обернуть подпись закрытия в круглых скобках, чтобы сделать закрытие необязательным. То, как оно написано сейчас, замыкает возвращает необязательный Void (что на самом деле не имеет смысла).

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

Некоторые точки стиля и изменения к вашему примеру:

 // Capitalize class names so it clear what 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]?) -> ())?

Кроме того, обратите внимание: я не думаю, что вы хотели сделать Bool необязательным (потому что, если существует ограничение, вы, вероятно, всегда передаете значение success true или false). Очевидно, что массив items может быть необязательным.

В любом случае, когда это будет сделано, вы просто убедитесь, что это необязательно:

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

Выполняет замыкание тогда и только тогда, когда оно не является nil, избегая необходимости явно проверять, было ли оно nil.


Для чего это стоит, это может быть случай, когда ваш typealias может сделать это менее запутанным:

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

Тогда свойство просто:

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.)