网站备案流程慢,建com网站,办公空间设计网站,铜川市住房和城乡建设局网站概览
SwiftUI 的出现极大的解放了秃头码农们的生产力。SwiftUI 中众多原生和自定义视图对于我们创建精彩撩人的 App 功不可没#xff01;
不过#xff0c;倘若小伙伴们略微留意过 SwiftUI 框架头文件里的源代码#xff0c;就会发现里面嵌有一些奇怪 Never 类型#xff0c…
概览
SwiftUI 的出现极大的解放了秃头码农们的生产力。SwiftUI 中众多原生和自定义视图对于我们创建精彩撩人的 App 功不可没
不过倘若小伙伴们略微留意过 SwiftUI 框架头文件里的源代码就会发现里面嵌有一些奇怪 Never 类型带来阵阵“违和感” 那么 Never 到底是一种怎样的存在它们在 SwiftUI 中又到底扮演着什么角色呢 在本篇博文中您将学到如下内容 概览1. 莫名其妙的”Never“2. 什么Never 竟然是一种”视图“3. Never 在 SwiftUI 视图中的作用4. 尝试创建一个自定义原生 “Never” SwiftUI 视图总结 闲言少叙Let‘s find out 1. 莫名其妙的”Never“
各位小伙伴们可能会奇怪 Never 到底表示什么如果没记错的话Never 的定义早在 SwiftUI 之前就已是 Swift3.0里的“囊中之物”了 从 官方代码的注释中可以清楚的看到 Never 存在的意义
/// The return type of functions that do not return normally, that is, a type
/// with no values.
///
/// Use Never as the return type when declaring a closure, function, or
/// method that unconditionally throws an error, traps, or otherwise does
/// not terminate.
///
/// func crashAndBurn() - Never {
/// fatalError(Something very, very bad happened)
/// }由上可知Never 在 Swift 中主要有两种用途
表示非正常返回方法或函数、闭包的返回类型比如抛出异常、断言等表示没有值的类型
比如虽然和实际返回类型不一致下面的 test 和 otherTest 方法都在某些错误条件下“返回” 了 Never 值
func test(a: Int, b: Int) - Int {guard b ! 0 else { fatalError()}return a/b
}func otherTest(items: [String]) - [String] {guard !items.isEmpty else { preconditionFailure(不能为空) }return items.map { $0.debugDescription }
}test(a: 10, b: 0)
otherTest(items: [])通过查看 fatalError() 和 preconditionFailure() 函数的定义我们发现它们哥俩都会返回 Never
public func fatalError(_ message: autoclosure () - String String(), file: StaticString #file, line: UInt #line) - Neverpublic func preconditionFailure(_ message: autoclosure () - String String(), file: StaticString #file, line: UInt #line) - Never同样Never 也可以用来表示某种类型“不存在”的值注意这种不存在和 nil 并不相同
let p PassthroughSubjectInt,Never()如上代码所示我们定义的 PassthroughSubject 发布器永远不会发生错误其错误类型为 Never
经过上面的讨论我们可以发现Never 的作用比想象的要大的多
值得注意的是作为枚举类型的 Never 不能被实例化至少我们从外部不能我们只能“享用”它们现成的实例。
那么Never 和 SwiftUI 又有怎样的关系呢
2. 什么Never 竟然是一种”视图“
是滴你没看错Never 在 SwiftUI 中做了扩展它确实可以表示为一种“视图”类型
available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension Never : View {
}available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension Never {/// The type for the internal content of this AccessibilityRotorContent.public typealias Body Never/// The internal content of this AccessibilityRotorContent.public var body: Never { get }
}比如我们耳熟能详的 VStack 定义中就有 Never 可爱的身影
available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
frozen public struct VStackContent : View where Content : View {inlinable public init(alignment: HorizontalAlignment .center, spacing: CGFloat? nil, ViewBuilder content: () - Content)public typealias Body Never
}而且Never 在 SwiftUI 不仅是一种视图它还可以是一种 ShapeStyle、 TableColumnContent、Gesture 甚至一种 Scene
available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension Never : ShapeStyle {/// The type of shape style this will resolve to.////// When you create a custom shape style, Swift infers this type/// from your implementation of the required resolve function.public typealias Resolved Never
}available(iOS 16.0, macOS 12.0, *)
available(tvOS, unavailable)
available(watchOS, unavailable)
extension Never : TableColumnContent {/// The type of sort comparator associated with this table column content.public typealias TableColumnSortComparator Never/// The type of content representing the body of this table column content.public typealias TableColumnBody Never/// The composition of content that comprise the table column content.public var tableColumnBody: Never { get }
}available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension Never : Gesture {/// The type representing the gestures value.public typealias Value Never
}available(iOS 14.0, macOS 11.0, tvOS 14.0, watchOS 7.0, *)
extension Never : Scene {
}看到这里小伙伴呢可能感觉有些“头晕目眩”。SwiftUI 里搞这么多 Never 到底是要闹哪样呢
3. Never 在 SwiftUI 视图中的作用
虽然很多小伙伴们都早已对 SwiftUI 撸码驾轻就熟不过大家有没有考虑过这样一个问题我们知道每个 View 都有一个 Body类型为 some View“爷爷”视图的 Body 是“爸爸”视图而“爸爸”视图的 Body 是“儿子”视图…这样下去会出现“子子孙孙无穷尽”的情况最终总要有一个最后的视图啊
比如观察下面的代码
struct Text: View {var body: some View {???}
}struct Son: View {var body: some View {Text(Son)}
}struct Baba: View {var body: some View {Son()}
}其中Baba 的 Body 中是 Son 视图而 Son 的 Body 嵌入的是 Text 视图那么 Text 里面又该怎么实现呢我们假设 Text 里面还有一个 InnerText 视图那么 InnterText 里又该如何
这就是 Never 在 SwiftUI 中存在的绝佳意义它终结了上面这种无穷尽的视图 Body 链
那么视图嵌套到底在哪里终结呢答案就是在 SwiftUI 内置的原生视图里。
比如在上面的例子中最终 Son 中里面是一个 Text 视图大家都知道 Text 视图是 SwiftUI 提供的众多原生视图之一。从码农的角度来看它不能再被分解从某种意义上可以认为它是一个“原子”视图
available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.0, *)
extension Text : View {/// The type of view representing the body of this view.////// When you create a custom view, Swift infers this type from your/// implementation of the required View/body-swift.property property.public typealias Body Never
}看到了吗SwiftUI 框架头文件里将 Text 的 Body 类型定义为了 Never正是这一个小小的 Never 将我们从“无穷无尽”中解脱出来整个世界变得清净了…
综上所述SwiftUI 不可能永远询问嵌套视图的 Body它需要特殊的视图比如那些“原子”视图作为“终结者”这样 SwiftUI 就可以停止“刨根问底”了。
我知道小伙伴们看到这里肯定会想如果我们自己创建返回 Never 的自定义视图会怎样呢
好吧下面就满足你们的“痴心妄想”
4. 尝试创建一个自定义原生 “Never” SwiftUI 视图
自己创建一个返回 Never 的 SwiftUI 视图很简单简直轻而易举
struct ImpossibleView: View {var body: Never {fatalError(感受一下炸弹的威力 )}
}编译没有任何问题但是运行呢 可以看到不出所料 App 在启动时被毅然决然的 Crash 掉了提示 SwiftUI/DynamicProperty.swift:338: Fatal error: ImpossibleView may not have Body Never 这是编译器在抗议视图的 Body 绝对不能为 Never 类型注意出错信息并不是我们期望的 “感受一下炸弹的威力 ”。
所以小伙伴们死心了吗将 Never 作为 Body 类型是 SwiftUI 内置原生视图“神圣而不可侵犯”的特权SwiftUI 在内部一定做了什么可以让原生视图“肆无忌惮”我们秃头码农只能在外面“干瞪眼”了。
至此我们彻底搞清楚了 Never 在 SwiftUI 中的“真正使命”大家的 SwiftUI 内功又更精进了一层棒棒哒
总结
在本篇博文中我们先是讨论了 Swift 语言中 Never 类型的起源以及 Never 在 SwiftUI 中的“真正使命”最后我们尝试了创建自己的 Never 视图。
感谢观赏再会