Swift4中重写UIRefreshControl属性类型不匹配报错求助
解决UITableView中UIRefreshControl重写冲突的问题
嘿,这个问题我在Swift4适配iOS11的时候踩过同款坑!
错误原因
你遇到的Cannot override mutable property 'refreshControl' of type 'UIRefreshControl?' with covariant type 'UIRefreshControl'错误,本质是:iOS11之后,UITableView已经自带了一个可选类型的refreshControl属性(类型为UIRefreshControl?),而你直接声明了一个非可选的同名属性var refreshControl = UIRefreshControl(),相当于试图覆盖系统的可变属性,但可选与非可选属于协变类型,Swift不允许这种类型不兼容的覆盖操作,因此抛出了错误。
解决方案
方案1:复用系统自带的可选属性(推荐)
不需要自己重新声明refreshControl,直接在viewDidLoad中初始化并赋值给系统属性即可:
override func viewDidLoad() { super.viewDidLoad() // 初始化刷新控件 let refreshControl = UIRefreshControl() refreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged) // 赋值给系统自带的可选属性 self.refreshControl = refreshControl } @objc private func handleRefresh() { // 这里编写你的下拉刷新逻辑,比如请求新数据 DispatchQueue.main.asyncAfter(deadline: .now() + 2) { // 数据加载完成后结束刷新 self.refreshControl?.endRefreshing() } }
方案2:自定义变量名(兼容老版本或特殊需求)
如果需要兼容iOS11以下版本,或者有特殊需求要自己管理控件,可以换个变量名避免冲突,然后手动添加到tableView:
// 自定义变量名,避免和系统属性冲突 private let myRefreshControl = UIRefreshControl() override func viewDidLoad() { super.viewDidLoad() myRefreshControl.addTarget(self, action: #selector(handleRefresh), for: .valueChanged) tableView.addSubview(myRefreshControl) // iOS10及以下需要设置contentInset,让刷新控件默认显示在导航栏下方 tableView.contentInset = UIEdgeInsets(top: myRefreshControl.frame.height, left: 0, bottom: 0, right: 0) } @objc private func handleRefresh() { // 刷新逻辑 DispatchQueue.main.asyncAfter(deadline: .now() + 2) { self.myRefreshControl.endRefreshing() } }
额外提示
iOS11之前,UITableView并没有内置refreshControl属性,那时我们确实需要手动声明并添加控件;但iOS11之后苹果将该属性整合到UITableView中,直接使用系统属性不仅更符合官方规范,还能自动处理控件的布局适配(比如和导航栏的联动),所以优先推荐方案1。
内容的提问来源于stack exchange,提问作者LF-DevJourney
相关产品推荐
相关产品推荐

