我使用以下代码片段(在Xcode 13 Beta 5
中,部署目标设置为14.0)根据iOS版本有条件地应用视图修改器:
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
将使它看起来像一盘千层面。
如何使这段代码以一种干净的方式编译,而不使用#available
检查?
5条答案
按热度按时间oug3syen1#
到目前为止,我认为最好的解决方案是为视图添加简单的修改扩展函数并使用它。如果修改量的可用性检查只在一个地方需要,这是有用的。如果需要在多个地方,然后创建新的修改量函数。
使用它将是:
编辑:
这允许我们在不需要的情况下不定义回退,并且视图将保持不可触及。
gxwragnw2#
没有'if #available'就没有办法做到这一点,但是有一种方法可以用一种比较干净的方式来构造它。
在 Package 视图上定义您自己的视图修改器:
然后,您可以按如下方式使用它们:
关于它的博客文章:Using iOS-15-only View modifiers in older iOS versions
4si2a6ki3#
您可以使用
@ViewBuilder
在View上创建简单的扩展要使用它,只需将其与现有视图链接即可
nkkqxpd94#
这没有意义,因为即使您向后移植了名为
task
的修饰符(这个问题通常是这样解决的)你将无法使用async/await的所有魔力,而这正是它的设计目的。如果你有一个很好的理由不针对iOS 15(我不知道有什么好的)然后继续正常使用onAppear
,在@StateObject
中使用标准的调度队列async或合并。yvfmudvl5#
对于您试图解决的问题,该修改器没有合理的用例!您不知道,您的应用会在每个渲染中检查您的iOS 15可用性条件多少次!也许1000次!控制数量太多,这是完全糟糕的主意!相反,对每个场景使用不同的视图,它只会检查一次: