我有一个迭代类别列表的方法,最后从所有类别返回项目。 简单的代码如下所示:
func iterateMyCategoriesItems(item:(_ category:Category) -> Void)
{
for category in allCategories
{
item(category)
}
}
使用时:
iterateMyCategoriesItems { (category) in
// doing something here with every category...
}
到目前为止一直很好,但现在我想为此方法添加一个可选的完成,所以我将代码更改为:
func iterateMyCategoriesItems(item:(_ category:Category) -> Void, _ completion:(() -> Void)? = nil)
{
for category in allCategories
{
item(category)
}
completion?()
}
但是现在当我尝试使用这样的方法时:
iterateMyCategoriesItems { (category) in
// doing something here with every category...
}
编译器显示错误:
在调用中缺少参数'item'的参数。
那么,我做错了什么?
答案 0 :(得分:2)
当你在函数末尾使用尾随{}
时,编译器会自动将它分配给函数的最后一个参数(到完成闭包),因此它认为你的调用中缺少items参数
您可以这样使用它:
iterateMyCategoriesItems (items:{ (category) in
// doing something here with every category...
})
或者如果你想完成
iterateMyCategoriesItems (items: { (category) in
// doing something here with every category...
}) { _ in
//do things when completed
}
答案 1 :(得分:1)
您应该能够在此调用中确定您正在使用尾随闭包:
iterateMyCategoriesItems { (category) in
// doing something here with every category...
}
Swift编译器检测到这是一个尾随闭包,因此它将它与方法的最后一个参数匹配,这是完成处理程序。
现在已经这样做了,它继续寻找与第一个参数匹配的其他参数。没有找到,所以它抱怨。
要解决这个问题,你必须放弃使用尾随闭包并正确传递参数:
iterateMyCategoriesItems(items: { (category) in
// doing something here with every category...
})
您还可以删除参数标签以使其更清晰。
答案 2 :(得分:1)
Swift book描述Trailing Closure如下:
如果需要将闭包表达式传递给函数作为 函数的最终参数,闭包表达式很长,它 将其作为尾随闭包编写是有用的。
(添加了大胆的风格。)
它明确地将目标参数称为最终。
即使最终参数是可选的,似乎此规则也适用。
//-> warning: closure parameter prior to parameters with default arguments will not be treated as a trailing closure
func iterateMyCategoriesItems(item:(_ category:Category) -> Void, _ someOptionalIntParam: Int? = nil)
{
for category in allCategories
{
item(category)
}
}
//-> error: missing argument for parameter 'item' in call
iterateMyCategoriesItems { (category) in
// doing something here with every category...
}
正如其他答案中已经提到的,如果你想保持你的功能定义:
func iterateMyCategoriesItems(item:(_ category:Category) -> Void, _ completion:(() -> Void)? = nil)
{
for category in allCategories
{
item(category)
}
completion?()
}
(这是另一个主题,但如果你想编写一个没有参数的闭包类型,你应该避免使用(Void)->Void
。参见this thread。)
你需要称之为:
iterateMyCategoriesItems(item: { (category) in
// doing something here with every category...
})
如果要将item
闭包始终作为尾随闭包编写,可以像这样修改函数定义:
func iterateMyCategoriesItems(completion:(() -> Void)? = nil, item:(_ category:Category) -> Void)
{
for category in allCategories
{
item(category)
}
completion?()
}
//Does not cause error
iterateMyCategoriesItems { (category) in
// doing something here with every category...
}
但是,您可能不希望在其他闭包之前放置completion
闭包。