咨询一个 Swift 语法问题

2021-08-04 18:42:42 +08:00
 BigDogWang

在 UIApplicationDelegate 里,有很多 application 函数。

函数名都是 application,但是参数不同

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool

func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data)

func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error)

我大致能猜到是兼容 oc 的语法?但是我想知道这个是什么特性?没有在文档中找到相关说明

还有这种:

func getTimeline(for configuration: Self.Intent, in context: Self.Context, completion: @escaping (Timeline<Self.Entry>) -> Void)

完全不了解其中的 for,in 有什么作用

1157 次点击
所在节点    问与答
10 条回复
BigDogWang
2021-08-04 18:49:11 +08:00
了解了,叫 外部参数名,真他娘的神奇
BigDogWang
2021-08-04 18:49:30 +08:00
感觉有点无法理解这种特性
finab
2021-08-04 18:52:52 +08:00
这些都是 swift 语法

application 确实是“兼容” oc 。UIApplicationDelegate 本身就是 oc 写的, 对应到 swift 语法就是这样。
_ 是省略第一个参数的外部参数名,oc 的方法一般第一个参数没有外部参数名
外部参数名和局部参数名你应该明白吧?

第二种其实就是普通参数外部名称,方便调用者知道传啥参数,参数可能有啥作用。
BigDogWang
2021-08-04 19:01:16 +08:00
@finab 感谢解答,现在都明白了,但是还是没有体会到这个特性的好处。以我目前的了解程度,就是多了一种函数重载的机制。

可能我再读读文档多用用就能明白深层次的含义了?

对于 Swift 这样兼容 OC 我也是不太理解。不过我不太了解 iOS 开发。

OC 可以将参数插入函数名之间,所以表现形式是这样,swift 要进行兼容完全可以将函数名合并起来,参数放到一起呀 😂
BigDogWang
2021-08-04 19:02:19 +08:00
至于方便调用者查看参数作用,文档加 形参 的命名应该也可以了
mxT52CRuqR6o5
2021-08-04 19:02:57 +08:00
第一个是不是函数重载?(没学过 swift )
qiuzhifei
2021-08-04 19:28:22 +08:00
函数重载,与 oc 无关
agagega
2021-08-04 21:06:31 +08:00
就是为了兼容 OC 那味,OC 的方法调用在 Runtime 实现成了消息传递 (objc_msgSend),这个鬼畜的语法也刻意做得跟 C 的函数调用不一样,比如下面这个方法:

- (void)tableView:(UITableView *)tableView
commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
forRowAtIndexPath:(NSIndexPath *)indexPath;

调用的时候差不多是:

[self tableView:myTable commitEditingStyle:myStyle forRowAtIndexPath:myPath]

这个方法(消息)的名字其实叫 tableView:commitEditingStyle:forRowAtIndexPath,也叫 selector,就是把每个带冒号的前缀都连在一起。每个冒号后面的就是消息带的参数。

Swift 继承了这个概念,但又要维持 C++风格的函数调用语法,所以每个参数默认都是具名的,调用的时候要加上名字和冒号。如果是不需要外部名字的,就在前面加个下划线。当然外部名字和内部名字可以不一样,所以你会看到冒号前面有两个名字的情况。像上面那个方法,在 Swift 里原型就是:

optional func tableView(_ tableView: UITableView,
commit editingStyle: UITableViewCell.EditingStyle,
forRowAt indexPath: IndexPath)

调用起来就变成了

self.tableView(myTable, commit: myStyle, forRowAt: myPath)

因为 OC 的方法实际上是没有所谓的「名字」的,而 Swift 有,所以这些官方 API 就把第一个冒号前面的名字拿来当方法名,而把第一个参数设置成非具名的。
BigDogWang
2021-08-04 21:44:02 +08:00
@agagega 感谢解答!非常详细,谢谢,明白了
Yunhao
2021-08-05 14:27:20 +08:00
这个是 Argument Labels,是 Swift 语言设计中的一个重要特性。这个特性本身并不是为了兼容 Oc,主要目的是增加可读性,可以看一看官方文档,例如 API 设计指南: https://swift.org/documentation/api-design-guidelines,看完你应该会明白这个特性的设计初衷是什么。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/793692

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX