Swift - 可选参数未按预期工作

时间:2017-07-22 11:47:20

标签: swift optional-parameters

我有一个迭代类别列表的方法,最后从所有类别返回项目。 简单的代码如下所示:

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'的参数。

那么,我做错了什么?

3 个答案:

答案 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闭包。