【问题标题】:Swift - optional parameter not working as expectedSwift - 可选参数未按预期工作
【发布时间】:2017-07-22 11:47:20
【问题描述】:

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

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”缺少参数。

那么,我做错了什么?

【问题讨论】:

    标签: swift optional-parameters


    【解决方案1】:

    当您在函数末尾使用尾随 {} 时,编译器会自动将其分配给函数的最后一个参数(完成闭包),因此它认为您的调用中缺少 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
    }
    

    【讨论】:

      【解决方案2】:

      您应该能够确定您在此调用中使用了尾随闭包:

      iterateMyCategoriesItems { (category) in
      
         // doing something here with every category...
      }
      

      Swift 编译器检测到这是一个尾随闭包,因此它将它与方法的最后一个参数(即完成处理程序)相匹配。

      现在它已经完成了,它会继续寻找与第一个参数匹配的其他参数。没有找到所以它抱怨。

      要解决这个问题,您必须放弃使用尾随闭包并正确传递参数:

      iterateMyCategoriesItems(items: { (category) in
      
         // doing something here with every category...
      })
      

      您还可以删除参数标签以使其更清晰。

      【讨论】:

        【解决方案3】:

        Swift bookTrailing Closure 的描述如下:

        如果您需要将闭包表达式作为 函数的final argument且闭包表达式很长,它 将其写为 尾随闭包 会很有用。

        (添加了粗体。)

        它清楚地将目标参数作为final

        即使最后一个参数是可选的,这条规则似乎也适用。

        //-> 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 闭包放在其他闭包之前。

        【讨论】:

        • 感谢您的回答!
        猜你喜欢
        • 2014-12-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-19
        • 2016-07-01
        • 1970-01-01
        • 1970-01-01
        • 2015-06-18
        相关资源
        最近更新 更多