7月 Swift记录

写在最前面

版本:Swift5,未使用Swift UI。
这也是我第一次写blog,不会使用markdown,也希望以后能够慢慢学一点markdown相关知识吧。

frame与自动布局

前话

在swift里面autoLayout的出现让布局变得更加简单,虽然autoLayout最后可能还是在实现上转换成了frame(个人猜想),但是frame和autoLayout总是“打架”,让人调试代码的时候哭笑不得。

一、采用自动布局的控件frame未形成

有的时候我们为了方便布局,无论是重新设置constraint,还是改变frame,都可能需要用界面上已经存在的元素来作为参考,但是事实上,在viewDidLoad()当中用自动布局放置的控件frame还没有明确(会有偏差)。

我过去尝试过:获取UIApplication.shared中的数据,或者使用GCD延后加载的方式。用第一种方式很麻烦,可能还找不到想要的参考;用第二种方式会影响用户体验。

现在,才明白我们需要在viewDidLoad() 的super.viewDidLoad() 后面的一行加上:

self.view.layoutIfNeeded()

在viewDidLoad中,view是加载成功了的,但是它的子view可能还没有加载成功,所以我们在这里就让他即时加载即可。如果暂时不知道是否需要使用到这些frame,无脑加一句上述代码也是可以的。

测试后发现,这只会影响view的直接子视图,层级更高的子视图不会受到影响。即内部的排列frame可能还是没有从autoLayout转换过来。
还有什么应用呢?比如我们现在有一个tableView是用的自动布局,我已经知道它是一个很小的列表,我希望他能够显示完整,为此我需要获取他的contentSize.height,只是这个时候内部的frame还没有形成,这会导致出现获取到0的情况。于是我们可以对tableView调用上述方法。然后内部的contentSize就改变了,我们把contentSize.height赋值给他的高度约束值。请注意如果section或者row的数目为0,那么contentSize.height也就是0了,直接赋值给约束可能会无法生效,可以尝试加上0.0001这样的小数字。

二、SafeArea

顾名思义,SafeArea是安全区,能够确保添加在安全区域内的元素不会被遮挡,容易遮挡界面重要元素的部分,举例:状态栏、全面屏机型的横条等。

对于非全面屏,SafeArea就是屏幕去掉状态栏。全面屏的SafeArea则是屏幕去掉状态栏和刘海区域、下方横条区域。
于是我们用下面的方法来判断当前机型是不是全面屏机型:

if let window = UIApplication.shared.keyWindow, window.safeAreaInsets.bottom > 0.0 {
    //do something if you want to
}

(因为第一次使用markdown,现在代码排版不会调……)

inset指的是边距,如果是全面屏,下方安全区的边距肯定是正数,非全面屏的边距则是0,可选值绑定的知识就不细说了。

另外,我还发现,获取设备的键盘高度时候,会考虑安全区。什么意思呢?我们来看下面的代码:

@objc func keyboardWillHide(notification: Notification){
    //得到键盘frame
    let userInfo: NSDictionary = notification.userInfo! as NSDictionary
    let value = userInfo.object(forKey: UIResponder.keyboardFrameEndUserInfoKey)
    let keyboardRec = (value as AnyObject).cgRectValue
    let kbheight = keyboardRec!.size.height
                
    if self.commentBar.frame.origin.y <= (self.view.bounds.height - kbheight){
        print("键盘收起,布局调整已启动")
        /* 直接写动画结果就好,不用调用animate方法
         * 因为在键盘弹出来的过程中,底端的动画操作会被忽略掉,只会考虑结束后的frame值
         */
        var frame = self.commentBar.frame
        frame.origin.y = self.view.bounds.height - self.commentBar.frame.height
        self.commentBar.frame = frame
        self.commentBarBottomConstraint.constant = 0
    }
        
}

在通知中心注册的通知事件中注册键盘事件,可以通过键盘的通知来获取键盘的高度。用这个方法获取的键盘高度包括了安全区域的高度(截至iPhone XS Max,这个安全区域的高度是34(1倍图中)),但是请注意,键盘却是从屏幕的最下端开始的(从主view的下端)。

对于传统机型,比如iPhone 8,这并无影响,因为安全区域的底部inset是0。但是对于全面屏机型,你将需要在处理键盘弹起后底部控件上移的过程中格外小心。

事实上,keyboard的高度是随时在变化的,下面我监听了键盘的每次弹出和收起,打印了下面的日志:
在这里插入图片描述
有些数据可能有点问题,但是可以看到稳定之后,数据集中在346和58。

另外顺便注意一下,键盘上方区域尽量减少透明元素使用,包括透明图片、有透明度的颜色等。这可能导致键盘弹出的画面闪动。因为重新规定约束后(目前是既要写frame,又要写约束),上方区域会再次变得不透明。可能解释的不太清楚,?但是尽量减少键盘上方区域透明元素使用(又说一遍)就是了。

三、约束不会立刻转换成frame

约束设定后,不会立刻被转换成frame。比如我在一个项目开发的过程中,写了下面的代码来测试:

print("之前的frame", commentAreaTableView.frame)
commentAreaTableViewHeightConstraint.constant = commentAreaTableView.contentSize.height + 0.001
print("之后的frame", commentAreaTableView.frame)

结果如下:
frame变化日志
想要使用setNeedsUpdateConstraints()和updateConstraintsIfNeeded()的时候失败了,暂时不清楚原因,没能立刻触发自动布局的转换。这里至少我们记住了自动布局和frame不会马上转换,但是会在后续的过程中实现转换的。而如果我们使用:

self.view.setNeedsLayout()
self.view.layoutIfNeeded()

则能够成功。

四、键盘弹出相关

设想下面的需求:屏幕最下面有一个输入框,需要在键盘弹出的时候输入框也跟着弹出。有下面的设置方式:

  1. 在键盘弹出的时候,设置frame,也设置约束。
    这将会出现动画,首先是用白色的背景遮住一部分区域,然后输入框随着键盘一起弹出。
  2. 在键盘弹出的时候,只设置frame,在键盘弹出之后再设置约束。
    输入框会随键盘一起弹出,但是输入框会被view中的其他部分遮住(如果上方区域有的话),也就是说,在图层上,这样弹出的输入框frame和约束是不能匹配上的,不处于第一图层。在键盘弹出之后,由于设置约束的代码运行,输入框的位置出现闪动,输入框又出现在第一图层。
  3. 在键盘弹出来的时候,设置约束,然后调用下面的方法:
self.view.setNeedsLayout()
self.view.layoutIfNeeded()

注意,这里的view恰好是输入框的直接父视图,使用的时候可能需要参照修改为其他视图。

这样就很完美了,和微信一样的弹出动画。

UITableView的坑

一、如何正确使用UITableView类

如果想要在UIViewController中使用这个类,要先让UIViewController继承几个必要的协议,然后在主视图加载完成的时候,把需要使用到的tableView的delegate和datasource设置成self即可。
设置完成之后,将需要实现协议中的几个方法。
注意,section的个数不能设置成0,如果只想要一个section,请设置成1,这里不是从0开始的。

系统调用的顺序是:先处理section、header和footer,然后处理cell的高度,然后处理cell里面的具体内容。(我还未使用过estimatedHeight,没有这个需求,详细的大家可以搜索一下tableView的优化,这方面的教程相当多。)

如果你使用了RxSwift框架、或者全新的SwiftUI,这一过程将会更加简单(但是也需要一定的学习成本)。

二、tableViewCell加载很卡或者滑动屏幕时掉帧

Swift为我们提供了重用策略,这将有效降低我们的加载时间。但是仍然可能出现卡顿现象。解决卡顿主要从几个方面入手:

1. 降低算法加载的复杂度

代理方法中,tableViewCell的高度、具体内容设置的方法在对每一个cell的加载过程都要调用,如果在这些方法中进行大量运算(尤其是结果一致但脱离函数范围被内存回收的重复运算)将会降低加载效率。建议在主视图加载完成之后就处理运算,并把需要的结果存储在全局变量中。

2.避免使用复杂的结构,视图应该相对简单

3.异步绘制图片

最开始可能很多人不会注意到tableView的卡顿问题,觉得官方给的框架优化的足够好,事实也确实如此。但是当图片足够多(特指比较大的图片,比如微信朋友圈中晒出来的图片)的时候滑动就不跟手了。我们发现在给cell指定具体内容的时候,如果过程较为复杂,可能发生线程阻塞。比如从数据库中获取数据,然后把Data类的数据转换成图片会比较耗时,给imageView指定图片并显示的渲染过程则更加耗时。对此我们建议异步进行图片绘制。可能的话,我们把label、textView等其他结构一并在异步绘制中完成,即把所有的图片都画到一张图上面,这样我们把所有的元素显示成一张图即可。如果需要交互操作(比如:点击),我们在相同的位置添加一个透明的按钮即可。

建议在给定cell具体内容的时候就进行异步绘制,而不是在tableViewCell的draw方法中进行异步绘制。我们会发现使用draw方法来绘制图片效率非常高,而且流畅丝滑,甚至比自己实现的更加完美,这得益于官方的优化。确实,draw也是异步绘制的。那为什么我不推荐使用draw呢?因为draw可能靠后调用,有一定的延迟时间,这样在对数据库获取数据的时候画图可能就会错位,这在我的开发过程中是必现的一个bug。

我尝试在tableViewCell给定内容的GCD方法中加上一定的延时,发现也会出现在draw方法中的窘境,而去掉延时则不会出现cell和数据的匹配错误。

如果有大神能够解决draw的问题就更好了,但是目前我确实不会处理匹配错误的问题,也不懂多线程的原理(苦笑)。

滚动视图拖拽时卡顿

  1. 开启上下反弹,并且让键盘在视图滚动时收起,遇到滚动到端点(不是一般滚动,还触发了Bounce的特性)会引起卡顿。我是在scrollViewDidEndDragging这个方法中让键盘收起来的,当拖拽结束的时候,遇到了端点,就会需要执行键盘收起、视图反弹两个操作,而在其他情况下,只会执行键盘收起一个操作,当然也不会卡。
    于是关闭了Bounce On Scroll,果然解决了问题。但是这样的滚动视图滚起来就很没有灵魂。
    所以正解是什么呢?应该在scrollViewWillBeginDragging中来写键盘收起。一方面可以避免拖拽完成的时候和反弹操作一起执行,界面负担加重或者出现操作。另一方面,一开始拖拽就收起键盘才应该是我们希望的,虽然我们平时滑动一下瞬间就完成了可能注意不到,但是实际上这很影响用户体验。

  2. 手机连接上电脑进行调试的时候可能会比较卡,尤其是在滚动界面收回键盘的时候,为了测试是不是程序真的会卡(固有bug),应该停止程序的调试,在手机上重复同样的操作,如果自己的代码写的没有问题,那么应该就不会卡了。

1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值