iOS Swift协议扩展封装一行调用ProgressView隐藏失效问题
问题根因
修改后进度条无法消失的核心问题有两个:
- 协议中声明的
progressView只有只读权限,无返回值的showProgressView内部创建的ProgressView是局部变量,没有赋值给控制器实例的progressView属性 - 调用
hideProgressView()时,guard let progressView = progressView永远读取到nil,后续移除视图的逻辑完全不会执行,已经添加到父视图的进度条自然无法被移除
正确实现方案
首先调整协议定义,给progressView增加写权限,同时定义你需要的一行调用的展示方法:
// 增加AnyObject约束,仅限类类型遵循,避免值类型的属性拷贝问题 protocol Loadable: AnyObject { var progressView: ProgressView? { get set } // 你需要的一行调用方法 func showProgress() func hideProgressView() }
在UIViewController的协议扩展中实现默认逻辑,内部自动处理进度条的创建、赋值、移除全流程:
extension Loadable where Self: UIViewController { func showProgress() { // 防止重复调用叠加多个进度条 guard progressView == nil else { return } let pv = ProgressView(frame: .zero) pv.alpha = 0 view.addSubview(pv) pv.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate(pv.setConstraints(boundsOf: view)) // 把创建的进度条实例赋值给存储属性,隐藏时才能正确获取 self.progressView = pv UIView.animate(withDuration: 0.3) { pv.alpha = 1.0 } } func hideProgressView() { guard let progressView = progressView else { return } UIView.animate(withDuration: 0.6) { progressView.alpha = 0.0 } completion: { [weak self] _ in progressView.removeFromSuperview() // 移除后置空属性,避免下次调用判断异常 self?.progressView = nil } } }
业务调用方式
控制器遵循Loadable协议后,不需要手动给progressView赋值,一行代码即可展示Spinner样式加载视图:
@objc private func loadData() { print("Calling API") // 一行调用展示进度条 self.showProgress() DispatchQueue.main.asyncAfter(deadline: .now() + 3.0){ [weak self] in self?.civilizationData() self?.hideProgressView() } }
优化点说明
- 增加重复调用校验,短时间多次触发
showProgress()不会叠加多个进度视图 - 动画闭包使用
[weak self]避免循环引用 - 进度条移除后主动将属性置空,保证状态一致性
- 初始状态将进度条alpha设为0,避免视图刚添加时的闪屏问题
内容的提问来源于stack exchange,提问作者Zeus Solomon Quijalvo Olivar
相关产品推荐
相关产品推荐

