Xcode 8:函数类型不能有参数标签,导致我的构建失败。

80

似乎出于某些原因,Swift选择使其编程不太易读,强制用户删除完成处理程序参数标签。我已经阅读了Swift讨论,仍然认为这是一个错误。至少他们可以将其设置为可选。

在使用Xcode 8构建时,有没有办法强制编译器使用Swift 2.3,以便我不再遇到这些错误?我已经更新了使用旧版Swift的选项(在构建设置下)legacy support in xcode,但我仍然遇到以下错误:

函数类型不能具有参数标签“isloggedIn”; 使用'_'代替

error Xcode 8

如何在完成处理程序中保留标签?

是的,它仍然不起作用。 - UKDataGeek
24
Swift 3明确禁止在函数类型中使用参数标签,这是一个值得质疑的选择,非常令人沮丧。 - Crashalot
17
令人沮丧和恼怒。我正在删除优秀的代码,以使其更难读懂且容易出错。 - UKDataGeek
13
我非常讨厌这个变化。 - UKDataGeek
5
似乎 Swift 3 试图追求过于哲学上的完美,而人类历史告诉我们这不是最有效的方法。非常讨厌 Swift 3 中的很多变化。 - funct7
显示剩余7条评论
5个回答

107

6
我同意这个观点,但它并不是解决方案。我建议我们努力提出一个提案,可能使这成为可选项。 - UKDataGeek
已将此作为当前解决方案添加,因为它的说明非常清楚。 - UKDataGeek
17
迄今为止,我在 Swift 3.1 中建议的解决方案仍未出现迹象 - 希望我们在 Swift 4 之前能够得到它。我非常讨厌这种改变! - UKDataGeek
@MatterGoal 当然你可以使用未命名的参数名称 -- $0 等等 -- 或者你可以使用命名参数。你只是不能强制 调用者 使用名称,但在函数内部参数可以被命名。 - Dan Rosenstark
直到那时,typealias 来拯救。如果 (isSuccess:Bool) -> Void 由于标签不允许,则我们可以有 typealias IsSuccess = Bool 并使用 (IsSuccess) -> Void - Saran
显示剩余3条评论

28

一个可考虑的解决方法。您无法执行:

func doStuff(completion: (foo: Int, bar: String) -> Void) {
    ...
    completion(foo: 0, bar: "")
}

...但你可以做:

func doStuff(completion: ((foo: Int, bar: String)) -> Void) {
    ...
    completion((foo: 0, bar: ""))
}

也就是说,您的闭包应该只有一个未命名的参数,该参数是元组,此处为(foo: Int, bar: String)

虽然这种方式有些丑陋,但至少您保留了参数标签。


1
有没有想法如何将此与typealias一起使用? public typealias ImageDataCompletion = (((imgData imgData: Data?, _ err: MYGR8TErrorClass?)) -> Void) 出现以下错误:... 元组元素不能有两个标签!!! 真是醉了??? - Anton Tropashko
@AntonTropashko: (((imgData imgData: Data?, _ err: MYGR8TErrorClass?)) -> Void) 应该改为 (((imgData: Data?, err: MYGR8TErrorClass?)) -> Void)。你试图给元组元素两次打标签。 - sam-w
2
这个解决方案的限制是元组不能只有一个值。 - Mark

14
基于上述信息,似乎真正修复并确保其高效的唯一方法是提出建议, 使参数标签成为可选项,以便:
  1. 提高开发速度(没有参数标签需要我们每次输入完成处理程序时向上滚动到方法顶部)。
  2. 减少错误:(我已经遇到了几个错误,因为不正确的完成处理程序条目,特别是那些期望布尔值的条目)。
  3. 使代码在团队成员之间更易读。并非每个人都只有一个团队成员,因此能够轻松地接收其他人的代码是必备的。
  4. 最后,良好的编程实践意味着解决方案应尽可能像正在开发的实际项目那样。completionhandler: (newvalues, nil) 看起来不像正在管理的项目,而 completionhandler(results: newValue, error:nil) 则不同。

我希望阅读这篇文章的人们可以在下面分享他们的反馈/评论,这样我就可以展示有其他人支持此举。

编辑: 我在这里提交了该提案:https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20161010/028083.html 它似乎已经被接受。看起来这将会发生,但讨论的是是否将其作为Swift 4的改进提交(非常可能)。


2
好的,既然你要求我发泄一下:这不是第一次开源程序员搞砸了某些东西(在他们宝贵的贡献之前可用)。阿门。 - Anton Tropashko
@AntonTropashko 在 Stack Overflow 上发泄,点个赞 - 希望你感觉好些了 ?? - UKDataGeek
点赞了答案!太解恼了!说真的:没有。 - Anton Tropashko
@MobileBloke,这个事情的进展如何?我没有看到它被纳入语言中... - frangulyan
不行 - 看起来已经被降低优先级了。这仍然很烦人。 - UKDataGeek

9
你需要使用_来使你的参数无名,这很不幸。我建议你不要将_添加到每个参数上,然后盲目地调用函数,而是建议制作一个包装器对象。
由于对于函数类型失去命名参数会增加调用函数时传递错误值的风险,我建议将参数封装在结构体中,并将其作为函数的唯一参数。
这样你的结构体字段就有名称了,并且只有一种类型的值可以传递到你的函数中。虽然比起能够命名函数参数来说更麻烦,但我们不能这样做。至少这样你会更安全,也会感觉不那么肮脏。
struct LineNoteCellState {

    var lineNoteText: String?
    var printOnInvoice = false
    var printOnLabel = false
}

下面是一个使用示例:
cell.configure(editCallback: { (_ state: LineNoteCellState) in

    self.lineNoteText = state.lineNoteText
    self.printOnInvoice = state.printOnInvoice
    self.printOnLabel = state.printOnLabel
})

6
半个解决方案,注意_
completion: (_ success: Bool) -> Void

2
这似乎对我来说没有自动完成-成功参数前的下划线功能是什么? - UKDataGeek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接