这儿每天共享一个 iOS 的新知识,快来重视我吧

前语

最近开始正式运用 SwiftUI 做项目了,但是发现了一个很大的问题,便是很多在 UIKit 中经常用的 API,在 SwiftUI 中需求很高的版别才能运用。

随便举几个比如,ScrollView 滚动关闭键盘的 keyboardDismissMode 特点,在 UIScrollView 中 iOS 7 就支撑了,但在 SwiftUI 中 iOS 16 才支撑。再比方,在 UIAlertController 上添加 TextField,在 UIKit 中 iOS 8 就支撑,但在 SwiftUI 上,iOS 16 才支撑。

所以现阶段不太可能用纯 SwiftUI 做项目,除非你的项目最低兼容 iOS 15,甚至是 16 以上。话说回来,在一些 API 低版别不支撑的状况下,就需求用到一些兼容手段,最近看到了一些聪明的办法共享给我们。

过错的兼容办法

我们假设你的项目最低版别支撑 iOS 14,在运用一些 14 上不兼容的 API 时会报错:

一种比较好的 SwiftUI API 兼容计划

能够看到 cyan 这个颜色在 iOS 15 才能运用,有一种办法是添加在这个 VStack 下添加 #available 判别:

var body: some View {
    if #available(iOS 16.0, *) {
        VStack {
            Text("Hello, world!")
                .fontWeight(.bold)
                .background(Color.red)
                .foregroundColor(.blue)
                .padding()
                .frame(width: 100, height: 100)
            Text("Hello, world!")
                .fontWeight(.bold)
                .background(Color.red)
                .padding()
                .frame(width: 100, height: 100)
                .foregroundColor(.cyan)
        }
    } else {
        VStack {
            Text("Hello, world!")
                .fontWeight(.bold)
                .background(Color.red)
                .foregroundColor(.blue)
                .padding()
                .frame(width: 100, height: 100)
            Text("Hello, world!")
                .fontWeight(.bold)
                .background(Color.red)
                .padding()
                .frame(width: 100, height: 100)
                .foregroundColor(.blue)
        }
    }
}

这种计划有几个问题,首要为了运用 cyan,整个 VStack 都要被 if 句子包裹起来,假如这个 VStack 下代码非常多的话,会有很多的重复代码。其次这种办法不利于保护,假如再有一个特点是 iOS 16 才能用的,那么再用 if iOS 16 包裹一次吗?显然不合理。

正确的做法

正确的办法是经过扩展做兼容,我们能够给 Color 扩展出一个新的 newCyan 特点,来兼容这种状况:

extension Color {
    static let newCyan: Self = {
        if #available(iOS 15.0, *) {
            return .cyan
        } else {
            return .black
        }
    }()
}

这样的话,再运用的时分直接运用 newCyan 就行了:

Text("Hello, world!")
    .foregroundColor(.newCyan)

这样就处理了上边的问题。

其他的比如

运用扩展的兼容计划是个不错的思路,还有一些其他比如:

1、隐藏 List 的分割线 listRowSeparator 办法,在 iOS 15 才能用:

一种比较好的 SwiftUI API 兼容计划

同样运用扩展:

func newHiddenListRowSeparator() -> some View {
    if #available(iOS 15.0, *) {
        return listRowSeparator(.hidden)
    } else {
        return self
    }
}

hiddenListRowSeparator 改成 newHiddenListRowSeparator 即可。

2、ScrollView 禁止滚动

func newScrollDisabled() -> some View {
    if #available(iOS 16.0, *) {
        return self.scrollDisabled(true)
    } else {
        return self
    }
}

3、View 的 tint 办法 iOS 15 以上才能用

那就给 View 写个扩展

extension View {
    func newTint(_ color: Color?) -> some View {
        if #available(iOS 16.0, *) {
            return self.tint(color)
        } else {
            return self.accentColor(color)
        }
    }
}

总结

运用扩展兼容 API 的办法优点清楚明了:

  1. 处理了重复代码问题

  2. 每个 API 的兼容判别都是独立的,可保护性强

  3. 当你晋级最低版别时,只需求把版别判别删掉或者直接把办法名改掉即可

这儿每天共享一个 iOS 的新知识,快来重视我吧

本文同步自微信大众号 “iOS新知”,每天准时共享一个新知识,这儿只是同步,想要及时学到就来重视我吧!