Комментарии 5
Не хочу обидеть автора, но кажется, что проблема немного надуманная, а такое решение - это код ради кода, а не действительно что-то полезное. Причем решение крайне небезопасное и по сути не решающее проблему - оно никак не способствует обязательному вызову completion, и мы точно так же не заметим баг до того, пока не попадем в багованную ветку, только при этом вообще получим краш в рантайме.
Кажется, что можно решить проблему куда проще и безопаснее, например так:
class SomeService {
func loadUser(completion: @escaping (Result<User, Error>) -> Void) {
let result: Result<User, Error>
defer { completion(result) }
// make request and handle result
}
}
Из минусов:
Приходится учитывать, что необходимо не вызывать completion самому, а использовать переменную result.
Из плюсов:
Не пишем никаких хитрых оберток, все очень понятно и прямолинейно.
Работает, наверное, вообще начиная со Swift 2 (если отбросить Result)
Самое главное: все проверки на этапе компиляции — если где-то ниже не присвоим result, то ошибка вылезет сразу. Это, кстати, сильно поможет с описанным выше минусом — если ты по привычке сделаешь
completion(...); return
, то компилятор сразу ругнется, что result не присвоен, и вероятно тут придется вспомнить, что вызов надо делать через переменную.Никаких ограничений на
@escaping
и@nonescaping
- подход работает где хочешь, делается в 2 строки.
Не знаю, реально ли автор пытался решать проблему, или это код чтобы потом сделать статью, но с учетом того, что оформлено оно в виде библиотеки на Github - даже не знаю, кто добровольно потащит себе такой костыль с fatalError'ами внутри
Как я понимаю Ваше решение только для синхронных функций подойдет.
Любой банальный async и работать не будет.
То что fatalError и его не стоит пихать туда - конечно, эт погорячились.
Но проблема такая существует.
> пока не попадем в багованную ветку
надо просто assert использовать и уже будет очень хорошо.
ну и можно написать тесты, если прям так хочется)
Вы зря фаталерроров боитесь. Это решение не отменяет ваше, а дополняет. Фаталеррор будет если кто-то применит Ваше решение неправильно. Если же правильно - то он никогда не сработает. То есть это последний рубеж обороны. Разбираться с двумя completion блоками или с невызванным блоком completion - то ещё сомнительное удовольствие - фаталеррор же во время QA сразу вылезет (ладно ладно может быть и не сразу). Впрочем тут про концепт. Впрочем всегда можно логирование ошибки вставить вместо фаталеррора - но тогда надо Void возвращать
// упс, здесь мы забываем вызвать comletion(...)!
// упс, мы забыли поставить
return
Ну так-то если забывать все подряд - никакие решения не помогут..
Можно еще забыть покрасить вьюшку в нужный цвет и начать пилить для этого решения
@Once: однократные замыкания