Время от времени мне приходится ходить по цепочке респондентов, чтобы добраться до экземпляра известного класса. (Просто примите это для целей вопроса.) Я делал это с помощью цикла while, но мне пришло в голову, что было бы круче использовать sequence()
, который может аккуратно выразить саму цепочку респондента следующим образом:
let chain = sequence(first: someView as UIResponder) {$0.next}
Это замечательно, потому что до сих пор мы на самом деле не ходили пешком; последовательность ленива, и анонимная функция не будет выполнена, пока мы не начнем запрашивать элементы. Чтобы доказать это, позвольте мне снабдить этот код инструкцией печати:
let chain = sequence(first: someView as UIResponder) {r in print(r); return r.next}
Хорошо, допустим, я ищу первый экземпляр ViewController в цепочке. Я могу найти это так:
if let vc = (chain.first {$0 is ViewController}) as? ViewController {
print(vc)
}
Распечатка показывает, что лень сохраняется: мы шли по цепочке респондента, пока не добрались до ViewController и остановились. Отлично! Внутри фигурных скобок vc
напечатано как ViewController, и мы отправляемся в гонки.
Это не ускользнуло от вашего внимания, однако, это ужасно. Я и тестирую и кастую. Есть ли способ, которым я могу просто привести без тестирования и все же получить ViewController?
Это элегантно и прекрасно работает:
for case let vc as ViewController in chain {
print(vc)
break
}
Это прекрасно, и лень сохраняется, - но я должен вспомнить, чтобы сказать break
в конце, что все разрушает.
Хорошо, так что я очень надеялся, когда думал об этом:
if let vc = (chain.compactMap{ $0 as? ViewController }.first) {
print(vc)
}
Он работает в том смысле, что он компилирует, получает правильный ответ и выглядит красиво, но я потерял лень . Весь chain
пересекается. compactMap
теряет лень? Есть ли способ вернуть его? (Или есть какой-то другой элегантный способ, который полностью ускользнул от меня?)