You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift 5.2中@objc无返回值函数自动补全显示删除线问题咨询

关于UIRefreshControl #selector中函数显示删除线的原因解析

嘿,这个现象其实是Xcode的代码提示逻辑和UIKit的Target-Action机制历史兼容细节共同导致的,我来给你理清楚:

1. UIKit Target-Action的签名历史

在Objective-C时代,UIControl(UIRefreshControl的父类)的action方法其实推荐带有返回值(通常是BOOL类型),用来决定是否继续传递事件到下一个响应者。不过很多控件(比如UIRefreshControl)本身并不关心这个返回值,所以无返回值的void方法也能正常触发——这是UIKit做的兼容处理。

2. Swift与Objective-C桥接的提示逻辑

当你用@objc标记一个无返回值的Swift函数时,它会被桥接成Objective-C的void方法。Xcode的代码补全系统会检测到这个方法和UIControl期望的“推荐action签名”不匹配,所以给它加上删除线,提示你“这不是最符合API设计的写法”——但这绝对不是方法被废弃,只是一个风格提示,所以程序运行完全正常。

3. 为什么加返回值就消除了删除线

当你给refresh_B加上Bool返回值后,它桥接成的Objective-C方法签名就变成了:

- (BOOL)refresh_B:(UIRefreshControl *)sender;

这个签名完全匹配UIControl期望的action方法格式,Xcode就认为这是“正确”的写法,删除线自然就消失了。而因为UIRefreshControl根本不会去读取这个返回值,所以你返回true还是false对功能没有任何影响。

补充说明

  • 这个删除线只是Xcode的代码提示,不影响编译和运行,如果你觉得看着别扭,要么加个返回值(像你做的那样),要么直接忽略它也没问题。
  • 除了加返回值,你也可以通过@objc重命名方法来规避提示,但完全没必要——加个返回值是最简单的解决方案。

附上你的最小复现代码,方便对应:

let refreshControl_A = UIRefreshControl()
let refreshControl_B = UIRefreshControl()

override func viewDidLoad() {
    super.viewDidLoad()
    refreshControl_A.addTarget(self, action: #selector(refresh_A(sender:)), for: .valueChanged)
    refreshControl_B.addTarget(self, action: #selector(refresh_B(sender:)), for: .valueChanged)
}

@objc func refresh_A(sender: UIRefreshControl) {
    print("Have strikethrough!")
}

@objc func refresh_B(sender: UIRefreshControl) -> Bool {
    print("No strikethrough!")
    return true
}

内容的提问来源于stack exchange,提问作者唐梓皓

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 19:23:13