SwiftUI:在没有 #available 的不同 iOS 版本之间使用视图修饰符

人气:479 发布:2022-10-16 标签: swiftui swift xcode13 swift5.5

问题描述

我使用以下代码片段(在 Xcode 13 Beta 5 和部署目标设置为 14.0)根据 iOS 版本有条件地应用视图修饰符:

I use the following code snippet (in Xcode 13 Beta 5 and deployment target set to 14.0) to apply view modifiers conditionally according to iOS version:

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .modifyFor(iOS14: {
                $0.onAppear {
                    //do some stuff
                }
            }, iOS15: {
                $0.task { //<---- Error: 'task(priority:_:)' is only available in iOS 15.0 or newer
                    //do some stuff
                }
            })
    }
}

struct CompatibleView<Input: View,
                      Output14: View,
                      Output15: View>: View {
    var content: Input
    var iOS14modifier: ((Input) -> Output14)?
    var iOS15modifier: ((Input) -> Output15)?
    
   @ViewBuilder var body: some View {
        if #available(iOS 15, *) {
            if let modifier = iOS15modifier {
                 modifier(content)
            }
            else { content }
        }
        else {
            if let modifier = iOS14modifier {
                 modifier(content)
            }
            else { content }
        }
    }
}

extension View {
    func modifyFor<T: View, U: View>(iOS14: ((Self) -> T)? = nil,
                                     iOS15: ((Self) -> U)? = nil) -> some View {
         CompatibleView(content: self,
                                  iOS14modifier: iOS14,
                                  iOS15modifier: iOS15)
    }
}

只要我不使用 iOS 15 的视图修饰符,此代码就可以很好地工作,但是如果我想使用这些修饰符中的任何一个(例如 Task),那么我需要使用#available 指令这是我不想选择的选项,因为我的代码库很大,有很多部分应该采用新的 iOS 15 修饰符并使用 #available 代码中的任何地方都会让它看起来像一盘烤宽面条.

this code works great as long as I don't use iOS 15's view modifiers, but if I want to use any of those modifiers (like Task for ex.) then I need to use the #available directive which's an option I don't wanna opt in, because my codebase is large, there are many parts that should adopt the new iOS 15 modifiers and by using #available everywhere in the code will make it looks like a dish of Lasagna.

如何在不使用#available检查的情况下以干净的方式编译这段代码?

how to make this piece of code compiles in a clean way and without using the #available check ?

推荐答案

没有意义,因为即使你向后移植了一个名为 task 的修饰符(这通常是解决这个问题的方式)您将无法在内部使用 async/await 的所有魔力,而这正是它的设计目的.如果您有充分的理由不针对 iOS 15(我不知道有什么好的理由),那么只需继续像往常一样使用 onAppear 和标准调度队列异步或在 @ 中组合状态对象.

There is no point because even if you did back-port a modifier named task (which is how this problem is normally solved) you won’t be able to use all the magic of async/await inside which is what it was designed for. If you have a good reason for not targeting iOS 15 (I don’t know any good ones) then just continue to use onAppear as normal and either standard dispatch queue async or Combine in an @StateObject.

138