SwiftUI的优缺点

2019年WWDC大会上,苹果在压轴环节向大众宣布了基于Swift语言构建的全新UI框架——SwiftUI,开发者可通过它快速为所有的Apple平台创建美观、动态的应用程序。推荐大量使用struct代替类。
SwiftUI 就是⼀种声明式的构建界面的用户接口工具包。
SwiftUI使用声明式的语法构建UI,我们只需要向系统声明UI的View样式,以及View如何转换状态,其他的过程都交给系统去处理。
SwiftUI的界面不再像UIKit那样,用ViewController 承载各种UIVew控件,而是一切皆View,所以可以把View切分成各种细致化的组件,然后通过组合的方式拼装成最终的界面,这种视图的拼装方式提高了界面开发的灵活性和复用性。因此,视图组件化是SwiftUI很大的亮点。
SwiftUI是声明式的构建方式,我们只需要声明好界面系统会自动转换状态,搭建界面更加的简单
声明式语法和指令式语法的区别:

声明式的我们需要提前声明好每个view的各种状态,以及状态转变的条件。后续界面和用户在互动时,系统会帮我们自动进行状态切换。
指令式的我们需要给每个view先设置好默认状态,后续界面和用户在互动时,需要通过指令不停的去转变view的状态
因此声明式的UI是提前声明好各种状态,系统会自动帮我们进行状态切换。指令式的UI是通过我们设定的指令来转换状态
比如界面调整、用户交互、机型适配,UIKit都需要手动调整view,对于SwiftUI我们只需要声明好我们想要的样式,系统会帮我们去调整view。
可以这么说,SwiftUI相比于UIKit更加的抽象化了
统一苹果终端
在 SwiftUI 出现之前,苹果不同的设备之前的开发框架并不互通,增加开发者所需消耗的时间精力,也不利于构建跨平台的软件体验
SwiftUI具有了跨平台性,苹果的平台都可以使用,iOS、macOS、tvOS、watchOS
降低界面开发难度
UIKit 的基本思想要求ViewController 承担绝⼤部分职责,它需要协调 model,view 以及⽤⼾交互。这带来了巨⼤的sideeffect 以及⼤量的状态
SwiftUI是声明式的构建方式,我们只需要声明好界面系统会自动转换状态,搭建界面更加的简单
更加高效
默认使用Metal渲染,性能非常高,比UIKit要好
更扁平化的内联数据结构去分配内存,值类型。占用内存很少(所以在轻应用的开发更适合使用SwiftUI)
代码量相比UIKit要更少,效率更高
更好的配合Swift语言
SwiftUI 使用了大量 Swift 的语言特性
声明式语法
与UIKit布局相比,更加的抽象化,只需要向系统声明界面样式以及样式变化条件,其他的系统会帮我们实现,不需要我们自己去调整视图
链式调用属性
链式调用是 Swift 语言的一种特性,就是使用函数式编程,可以像链条那样不断地调用函数,中间不需要断开。使用这种方式可以大大减少代码量。
除了系统提供的属性可以使用之外,开发者也可以进行自定义
例如将不同字体、字号、行间距、颜色等属性统合起来,可以组合成为一个叫「标题」的文字属性。之后凡是需要将某一行文字设置成标题,直接添加这个自定义的属性即可,使用这种方式进行开发无疑能够极大的避免无意义的重复工作,更快的搭建应用界面框架。
界面元素的组件化
UIKit耦合了很多的操作逻辑,很难进行移植,更遑论组件化了
而SwiftUI仅仅声明界面样式,所以是可以将复杂视图的拆分出来组件化
甚至还可以在其他平台使用,以此跨平台
一般我个人会将视图组件区分为基础组件、布局组件和功能组件
与UIKit互相兼容
把 UIKit 中已有的部分进行封装,提供给 SwiftUI 使用。开发者需要做的仅仅是遵循UIViewRepresentable协议即可
并且在已有的项目中,也可以仅用 SwiftUI 制作一部分的 UI 界面
两种代码的风格是截然不同的,但在使用上却基本没有性能的损失。在最终的运行效果上,用户也无法分辨出两种界面框架的不同。
真实数据源(Source of truth)(重点)
SwiftUI中的数据源一定会是真实的,也就是准确的
在OC中,一个view的状态由多种因素导致的,不同的来源,不同的逻辑操作(因此需要考虑及时更新界面)
因此在Swift中,提供了单一数据源的说法
只要在属性声明时加上 @State 等关键词,就可以将该属性和界面元素联系起来,在每次数据改动后,都有机会决定是否更新视图。
系统将所有的属性都集中到一起进行管理和计算,也不再需要手写刷新的逻辑。
因为在 SwiftUI 中,页面渲染前会将开发者描述的界面状态储存为结构体,更新界面就是将之前状态的结构体销毁,然后生成新的状态。
而在绘制界面的过程中,会自动比较视图中各个属性是否有变化,如果发生变化,便会更新对应的视图,避免全局绘制和资源浪费。
使用这种方式,读和写都集中在一处,开发者就能够更好地设计数据结构,比较方便的增减类型和排查问题。而不用再考虑线程、原子状态、寻找最新数据等各种细节,再决定通知相关的界面进行刷新。

UIKit 的基本思想要求ViewController 承担绝⼤部分职责,它需要协调 model,view 以及⽤⼾交互。这带来了巨⼤的sideeffect 以及⼤量的状态

SwiftUI不仅为Apple的平台带来了一种新的构建UI的方式,还有全新的Swift编码风格;
可以推断出:SwiftUI会出现很多组件库,方便前端开发;
支持热更新,这一点可能让更多的开发者拥抱SwiftUI;
虽然SwiftUI优点很多,但是其使用的门槛很高,只能在iOS 13以上的系统使用;仅这点,很多公司和开发者望而却步,目前主流应用最低支持iOS 9,至少3年之内,SwiftUI只能作为一个理论的知识储备,所以其还有很长的路要走;
说了它的优点,再说下它的缺点:
1.由于大量Struct来实现页面,甚至事件处理也写在Struct里面。要知道在Struct里是无法打印日志,这样造成无法建立强大的日志跟踪功能。一个好的软件一定要一个强大的日志跟踪系统。上次我开启了苹果的iOS内存日志功能,发现两个页面切换一次打印的日志就达到50兆–100兆的日志。可见苹果的内存管理好,是靠多少人的不断努力和打印跟踪内存分配和使用,只是对我们应用层开发者屏蔽了大量底层细节。自己的方便是建立在他人辛苦上的,没有无缘无故的方便。
2.由于大量Struct来实现页面,它没有deinit(类似oc的dealloc函数)。这样造成无法跟踪页面和view等的内存释放跟踪,定位是否有内存泄漏。无法使用采用hook技术的MLeaksFinder库检查是否内存泄漏。当然部分Struct可以用final class代替,但是和它提倡的采用Struc减少内存相悖。实际上采用SwiftUI大都采用Struct
3.由于大量Struct来实现页面,闪退时无法打印出页面的类名,日志跟踪时也显示不出页面的类名。点击UI View Hierarchy,打印的页面View是看不懂的内容,如:TtGC7SwiftUI14_UIHostingViewVS_7AnyView: 0x109d12880。不是正确的类名。并且页面层级稍微多两层,点击UI View Hierarchy就可能出不出来UI View Hierarchy了。这很不利于我们定位当前页面是那个类。
在这里插入图片描述
看到无法打印当前在那个页面的view,无法根据打印内存在工程中搜索到对应的view,不利于熟悉代码。

在这里插入图片描述
这个是开启僵尸进程后看到的闪退日志,可以看到无法看到那个类闪退了。
在这里插入图片描述
这个是oc的页面层级结构,可以看到各个组件层级很清晰,页面类名显示的很清晰,一个不熟悉代码的人很容易找到对应页面类,找到对应页面,很容易熟悉代码。
4.由于SwiftUI采用的是盒子的设计概念。手机加载时由于内存问题,通常用表格实现下拉内容多的页面,采用表格复用减少内存加载。而SwiftUI在用VStack实现下拉时可能遇到上下滑动时,页面元素乱飞的不可思议场景。不知道如何解决。

struct ChannelSingleView: View {
    @EnvironmentObject var server: ServerManager
    @EnvironmentObject var geoHallModel: GeoHallViewModel
    @EnvironmentObject var messageViewModel: MessagePageViewModel
    var channel: ServerResponse.ChannelModel
    var idx: Int
    var angle: Double {
        if let id = channel.id {
            return geoHallModel.channelAngleDict[id] ?? 0.0
        }
        return 0.0
    }

    private var isSelected: Bool {
        return channel.id == geoHallModel.currChannel?.id
    }

    var body: some View {
        VStack(alignment: .center, spacing: 0) {
            channelAvatar
                .rotation3DEffect(.degrees(angle), axis: (x: 0, y: 1, z: 0.2))

            if let name = channel.name {
                Text(name)
                    .styleText(.size12, .black)
            }
        }
        .frame(width: 51 * .pointRatio)
        .overlay {
            Color.bgcGray.opacity(isSelected ? 0 : 0.7)
        }
        .animation(.default, value: channel.top)
        .id(channel.id)
        .onTapGesture {
            if !isSelected {
                let canChangeTab = CustomTempVars.shared.canChangeTab
                if canChangeTab {
                    CustomTempVars.shared.canChangeTab = false
                    Task {
                        var channel = channel
                        channel.roomID = await server.getChannelRoom(channel.id ?? "")
                        geoHallModel.switchChannel(channel)
                    }
                    withAnimation(.interpolatingSpring(stiffness: 20, damping: 5)) {
                        if let id = channel.id {
                            geoHallModel.channelAngleDict[id]! += 360
                        }
                    }
                }
            }
            geoHallModel.clearReadDot(channel)
        }
        .ignoresSafeArea()
        .padding(.trailing, .size05)
        .padding(.leading, .size05)
//        .padding(.trailing, 9 * .pointRatio)
        .padding(.top, .safeAreaTop + .size05)
        .padding(.bottom, .size05)
//        .padding(.leading, 9 * .pointRatio)
    }
}

在这里插入图片描述
这个是正常页面

在这里插入图片描述
这个是下滑后上滑动页面元素乱跳的一种场景

5.因为SwiftUI是一切皆view,大量使用Struct,当实现所有页面默认失败页面和无数据时,oc是采用ViewController基类快速实现,不知道SwiftUI实现。
6.当页面发送网络请求时,一般需要一个蒙层和动画,防止用户重复触发请求导致各种异常。oc是采用第三方控件在keywindow加入蒙层和动画的方式实现。SwiftUI可能有,我是不知道。这就是需要技术栈的积累问题。
7.当A页面进入B页面,B页面查询数据时,报错需要弹出toast弹窗,并退出B页面到A页面。一般toast弹窗是现实在keywindow上的,但是kewindow是B页面,而由于自动返回A页面,B页面销毁了,就看不到这个toast弹窗了。使用MBProgressHUD时就会遇到该问题。有的app为了解决这个问题人为延迟推出B页面,这样降低用户的体验流畅度,不完美。另一用采用SVProgressHUD来实现,它是异步时弹窗,显示调用弹窗和实际显示弹窗有一个时间差,正好在B页面调用弹窗,在回到A页面时,弹窗出来,所以能显示出来。我们遇到过一个问题,一个请求后台在时机毫秒内返回,蒙层弹窗还没有出来请求回来了,并且取消弹窗,实际上SVProgressHUD还没有出来,导致后面没有取消处理了,一直在哪里转圈了。最佳解决方案是创建一个优先级高于当前级别的window显示蒙层和动画。不知道SwiftUI处理这些细节问题。
8.SwiftUI提倡view组件化,可能产生view处理过多,不利于专类做专门的事情的原则。要平衡view的复杂性和复用性,不推荐过度的复用。
一个完美的产品不是完成基本功就完事,要完美处理各种细节。SwiftUI在技术栈积累不够和各种组件前不建议实际应用。作为知识储备是必要,立即实施风险太大,没有必要。我们很欣赏SwiftUI简洁性和快速开发,很多细节需要我们解决。方便和功能强大是相悖的。正如java和C/C++的关系。使用java基本不关注指针使用和内存使用,方便好学。C/C++需要处理烦人的指针和内存使用问题,正因为它更接近底层,所以能实现java实现不了的问题和响应比java快30%。一个好的软件不取决于采用那种语言,而是取决于开发软件的人。SwiftUI还任重道远,不要过于追求新技术。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/35859.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器学习与深度学习——自定义函数进行线性回归模型

机器学习与深度学习——自定义函数进行线性回归模型 目的与要求 1、通过自定义函数进行线性回归模型对boston数据集前两个维度的数据进行模型训练并画出SSE和Epoch曲线图,画出真实值和预测值的散点图,最后进行二维和三维度可视化展示数据区域。 2、通过…

SpringBoot + Vue前后端分离项目实战 || 五:用户管理功能后续

系列文章: SpringBoot Vue前后端分离项目实战 || 一:Vue前端设计 SpringBoot Vue前后端分离项目实战 || 二:Spring Boot后端与数据库连接 SpringBoot Vue前后端分离项目实战 || 三:Spring Boot后端与Vue前端连接 SpringBoot V…

企业内部安全:利用 ADAudit Plus 管理与加强安全审计

在现代数字化时代,企业面临着日益复杂和不断变化的安全威胁。为了保护敏感数据、遵守合规要求以及防范内部威胁,企业需要有效的安全审计解决方案。ADAudit Plus 是一款强大而全面的安全审计工具,可以帮助企业管理和加强内部安全。 ADAudit Pl…

Jenkins持续集成,在Linux中安装最新版Jenkins(详细)

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 去年从6月28日发布…

git学习1

打标签 与其他版本控制系统(VCS)一样,Git 可以给仓库历史中的某一个提交打上标签,以示重要。 比较有代表性的是人们会使用这个功能来标记发布结点( v1.0 、 v2.0 等等)。 列出标签 在 Git 中列出已有的…

SpringCloud:微服务技术

一、认识微服务: 首先,微服务架构不等于SpringCloud,微服务架构是一种经过良好架构设计的分布式架构方案, ,它将应用构建成一系列按业务领域划分模块的,小的自治服务,并解决服务拆分所产生的各种…

github搜索技巧笔记

一、了解 GitHub Watch按钮 Watch可以理解为关注的意思,默认情况下是Not watching,当选择Watch后,你会收到这个GitHub项目的所有动态。比如:有人发起pull request或者issue等。接收动态方式包括个人通知中心或者邮箱。 如果某个…

GIT版本控制常规性操作演示汇总

文章目录 GIT基本操作GIT配置个人信息配置:GIT查看个人信息配置:GIT的三大区域GIT回滚:git resetGIT恢复日志:git reflogGIT三大区域转换GIT新建分支GIT合并分支GIT删除分支码云上创建项目GIT变基:git rebase合并提交记…

设计模式- 一、设计原则-1

一、设计原则 当涉及到软件设计和开发原则时,有一些常见的原则和准则可以帮助我们编写高质量、可维护和可扩展的代码。以下是其中一些重要的原则和准则: SOLID原则: 单一职责原则(Single Responsibility Principle,SRP…

举例说明ChatGPT模型是怎么进行无监督学习的

ChatGPT,也称为生成式预训练Transformer(GPT),是一种基于Transformer架构的自然语言处理模型。虽然在实际应用中,它主要用于有监督学习任务,但在训练初期,它会经历无监督学习阶段。以下是一个简…

【简单认识LVS及LVS-NAT负载均衡群集的搭建】

文章目录 一、LVS群集简介1、群集的含义2、性能扩展方式3、群集的分类4、负载均衡群集架构1、负载均衡的结构 5、三种负载调度工作模式1、NAT模式2、TUN模式3、DR模式 二、LVS虚拟服务器1、Linux Virtual Server简介2、启用LVS虚拟服务3、LVS调度算法(1)…

Atcoder Beginner Contest 309——D-F讲解

前言 由于最近期末考试,所以之前几场都没打,给大家带了不便,非常抱歉。 这个暑假,我将会持续更新,并给大家带了更好理解的题解!希望大家多多支持。 由于, A ∼ C A\sim C A∼C 题比较简单&am…

Git 上传Github 超时问题

提交代码到GitHub总是超时,偶尔会直接上传成功。 提供一下解决方案 1.首先找到网络 2. 找到代理 3. 把自动检查设置全部关闭,然后打开手动设置代理,然后输入ip地址和你代理的端口号,保存即可。 4. 最后使用git push origin mast…

java中如何将一个集合list转成以逗号隔开的字符串

事例代码 代码&#xff1a; package com.air.app;import java.util.ArrayList; import java.util.List;public class ListToStringTest {public static void main(String[] args) {//定义list集合List<String> list new ArrayList<>();list.add("1");…

基于低代码平台打造的焙乐道销售支持系统

编者按&#xff1a;低代码平台说了那么多&#xff0c;在实际应用中又是怎样体现的它的种种优势呢&#xff1f;今天小编结合实际案例来说说。 本文是以最大的烘焙原料产商——焙乐道的销售支持系统为例子&#xff0c;进行说明。 客户说明&#xff1a;焙乐道是一家国际性集团公司…

Python一行命令搭建HTTP服务器并外网访问+-+内网穿透

文章目录 1.前言2.本地http服务器搭建2.1.Python的安装和设置2.2.Python服务器设置和测试 3.cpolar的安装和注册3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 转载自远程内网穿透的文章&#xff1a;【Python】快速简单搭建HTTP服务器并公网访问「cpolar内网穿透…

CentOS Linux上安装JDK11、MySQL8.0、Minio等软件(rpm脚本模式)

本地环境&#xff1a;Windows 10家庭版 16G内存 512G硬盘 软件&#xff1a;VMWare WorkStation 16.0 FinalShell 4.0.1 一、下载必要软件包 下载软件均选择x86架构64位&#xff01;&#xff01;&#xff01;&#xff08;可根据自己的电脑配置选择&#xff09; CentOS Linu…

数字图像处理(三)

目录 实验六、图像分割方法 实验七、图像识别与分类 实验六、图像分割方法 一、实验目的 了解图像分割技术相关基础知识&#xff1b;掌握几种经典边缘检测算子的基本原理、实现步骤理解阈值分割、区域分割等的基本原理、实现步骤。理解分水岭分割方法的基本原理、实现方法。…

ModaHub魔搭社区:Zilliz Cloud快速开始教程(一)

目录 前提条件 创建 Collection 查看 Collection 插入数据 本教程涵盖以下 Zilliz Cloud 集群操作指南: 创建 Collection查看 Collection插入数据向量搜索、向量查询、通过 ID 获取 Entity删除 Entity删除 Collection 前提条件 在本文档中,我们将使用 Milvus 的 SDK。…

mysql单表查询,排序,分组查询,运算符,select,order by,group by

CREATE TABLE emp (empno int(4) NOT NULL, --员工编号ename varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,--员工名字job varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,--员工工作mgr int(4) NULL DEFAULT NU…