
Когда на Catalyst пишется приложение для macOS, недоступны некоторые модификаторы View. Например, простой refreshable(action:). Его использование вызывает ошибку не компиляции, а исключение в рантайме:
[General] SwiftUI.SwiftUI_UIRefreshControl is not supported when running Catalyst apps in the Mac idiom. See UIBehavioralStyle for possible alternatives. Consider using a Refresh menu item bound to ⌘-R
Из-за этого можно пропустить в продакшн код, который на платформе не работает на самом деле.
Исправить положение можно, отказавшись от модификатора и его функций, можно написать разные компоненты под разные платформы, но есть способ удобнее и лучше: собственный ViewModifier.
Для этого воспользуемся сниппетом для определения платформы от Peter Steinberger из этого поста:
extension UIDevice {
var isCatalystMacIdiom: Bool {
if #available(iOS 14, *) {
return UIDevice.current.userInterfaceIdiom == .mac
} else {
return false
}
}
}
И с его помощью реализуем примитивный по своей сути модификатор:
struct SafeRefreshable: ViewModifier {
let action: @Sendable () async -> Void
func body(content: Content) -> some View {
if UIDevice.current.isCatalystMacIdiom {
content
} else {
content.refreshable(action: action)
}
}
}
В нём просто возвращаем content на macOS, которая не поддерживает интересующий нас модификатор SwiftUI. К сожалению, непосредственное использование кастомного модификатор предполагает написание некрасивого кода:
.modifier(SafeRefreshable(action: action))
Исправим это добавив в проект категорию для View:
extension View {
func safeRefreshable(action: @escaping @Sendable () async -> Void) -> ModifiedContent<Self, SafeRefreshable> {
return modifier(SafeRefreshable(action: action))
}
}
Теперь модификатор в коде выглядит нативно:
.safeRefreshable { await refresh() }
Приятного кодинга!