Как быстро сделать необязательное закрытие?

93

Я пытаюсь объявить аргумент в Swift, который требует дополнительного закрытия. Объявленная мною функция выглядит так:

class Promise {

 func then(onFulfilled: ()->(), onReject: ()->()?){       
    if let callableRjector = onReject {
      // do stuff! 
    }
 }

}

Но Swift жалуется, что «связанное значение в условном выражении должно быть необязательным типом», где объявлено «if let».

Маркоск
источник
Рассмотрите возможность использования только одного закрытия с параметрами.
catanore

Ответы:

113

Вы должны заключить необязательное закрытие в круглые скобки. Это позволит правильно определить область действия ?оператора.

func then(onFulfilled: ()->(), onReject: (()->())?){       
    if let callableRjector = onReject {
      // do stuff! 
    }
 }
Цезарь
источник
Знаете ли вы, в чем причина необходимости заключать это в круглые скобки?
Marcosc
5
Наверное, чтобы убрать двусмысленность. Если бы необязательное закрытие должно было иметь возвращаемое значение, это могло бы сбить с толку, что ()->Int?означает.
Cezar
3
Кроме того, из книги Swift: «При объявлении необязательного типа обязательно используйте круглые скобки, чтобы правильно указать? оператор. Например, чтобы объявить необязательный массив целых чисел, запишите аннотацию типа как (Int []) ?; писать Int []? выдает ошибку. "
Cezar
@Cezar Не могли бы вы немного объяснить, почему и где использовать «Необязательное закрытие», мне любопытно это узнать.
iLearner
@Cezar На данный момент нет на Mac, поэтому мой синтаксис может быть немного неправильным, но помните, что на ?самом деле это просто сахар Optional<T>, поэтому вы также можете написать `func then (onFulfilled: () -> (), onReject: Optional <() -> ()>) {`тогда вам не понадобится лишнее (), хотя, по-моему, ()?он красивее. Также вы можете сделать его еще красивее с помощью типажей вроде typealias RejectHandler = () -> () func then(onFulfilled: ()->(), onReject: RejectHandler?) {
Эндрю Картер,
63

Чтобы сделать код еще короче, мы можем использовать nilзначение по умолчанию для onRejectпараметра и необязательную цепочку ?()при его вызове:

func then(onFulfilled: ()->(), onReject: (()->())? = nil) {
  onReject?()
}

Таким образом, мы можем опустить onRejectпараметр при вызове thenфункции.

then({ /* on fulfilled */ })

Мы также можем использовать синтаксис завершающего закрытия для передачи onRejectпараметра в thenфункцию:

then({ /* on fulfilled */ }) {
  // ... on reject
}

Вот сообщение об этом в блоге .

Евгений
источник
34

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

func then(onFulfilled: ()->(), onReject: ()->() = {}){       
    // now you can call your closures
    onFulfilled()
    onReject()
}

эту функцию теперь можно вызывать с onRejectобратным вызовом или без него

then({ ... })
then({ ... }, onReject: { ... })

Здесь нет нужды в крутом Swift Optionals?!

ДиегоФрингс
источник
Хорошее решение!
Roland T.
6

Может, это более чистый способ. Особенно, когда у укупорки сложные параметры.

typealias SimpleCallBack = () -> ()

class Promise {

func then(onFulfilled: SimpleCallBack, onReject: SimpleCallBack?){       
    if let callableRjector = onReject {
        // do stuff! 
    }
}

}
Сейфолахи
источник