1

I'm relatively new to Swift and am receiving a Multiple Closures with Trailing Closure Violation:... warning from SwiftLint. My code that causes this looks like the below. Any idea on how I can refactor my code so that it doesn't violate SwiftLint. Thanks so much for your help

let RepaymentCoordinator = PayCoordinator(
    deLinkedErrorCompletion: { topvc, account in
        self.delinkedErrorCompletion(topvc, account: account)
    }
) { [weak self] _, isPayNowCallCompleted in
    guard let self = self else { return }
    if self.accountDetailsCoordinator != nil, isPayNowCallCompleted {
        self.accountDetailsCoordinator?.reloadBuyNowPayLaterAccountDetails()
    }
}

The PayCoordinator.init:

public init(
    topViewController: UIViewController,
    repaymentProvider: BuyNowPayLaterRepaymentProvidable,
    deLinkedErrorCompletion: @escaping BuyNowPayLaterRepaymentCoordinatorDeLinkedErrorCompletion,
    flowDidFinishCompletion: @escaping BuyNowPayLaterRepaymentCoordinatorFlowDidFinishCompletion
) {
    self.topViewController = topViewController
    self.repaymentProvider = repaymentProvider
    self.deLinkedErrorCompletion = deLinkedErrorCompletion
    self.flowDidFinishCompletion = flowDidFinishCompletion
    super.init()
}
Rob
  • 415,655
  • 72
  • 787
  • 1,044
rainerwolfram
  • 31
  • 1
  • 3
  • Change the trailing closure to a named parameter as with `deLinkedErrorCompletion` – Paulw11 May 26 '22 at 20:45
  • Thanks for your reply. Can you possibly show me this, I tried this but couldn't seem to get it right. Thanks so much – rainerwolfram May 26 '22 at 20:55
  • What is the Parameter name of your trailing closure? What does the declaration of `PayCoordinator.init` look like? – Paulw11 May 26 '22 at 20:56
  • `public init( topViewController: UIViewController, repaymentProvider: BuyNowPayLaterRepaymentProvidable, deLinkedErrorCompletion: @escaping BuyNowPayLaterRepaymentCoordinatorDeLinkedErrorCompletion, flowDidFinishCompletion: @escaping BuyNowPayLaterRepaymentCoordinatorFlowDidFinishCompletion ) { self.topViewController = topViewController self.repaymentProvider = repaymentProvider self.deLinkedErrorCompletion = deLinkedErrorCompletion self.flowDidFinishCompletion = flowDidFinishCompletion super.init() }` – rainerwolfram May 26 '22 at 21:05
  • Just so you know, SwiftLint has a decent [rules documentation](https://realm.github.io/SwiftLint/rule-directory.html). Click on the rule you're interested in and you'll see a page with the explanation and examples (both triggering and non-triggering). – Vadim Belyaev May 26 '22 at 21:19

1 Answers1

3

See SE-0279 for contemporary syntax when dealing with multiple closures. This is reiterated in The Swift Programming Language: Closures: Trailing Closures, which summarizes this new convention as follows:

If a function takes multiple closures, you omit the argument label for the first trailing closure and you label the remaining trailing closures.

In your case, the init method you supplied in the comments had two parameters you didn’t supply in your question, but I’m assuming you omitted them for brevity. But adding them back, SE-0279 would indicate one of the following:

let coordinator = PayCoordinator(topViewController: topVC, repaymentProvider: provider) { topVC, account in 
    // ...
} flowDidFinishCompletion: { [weak self] _, isCompleted in 
    // ...
}

Note the absence of the comma before flowDidFinishCompletion.

Or, alternatively:

let coordinator = PayCoordinator(
    topViewController: topVC, 
    repaymentProvider: provider
) { topVC, account in 
    // ...
} flowDidFinishCompletion: { [weak self] _, isCompleted in 
    // ...
}

For the sake of completeness, you can also silence the error if you simply avoid trailing closure syntax entirely, and employ labels on both closures. E.g.,

let coordinator = PayCoordinator(
    topViewController: topVC, 
    repaymentProvider: provider,
    deLinkedErrorCompletion: { topVC, account in 
        // ...
    },
    flowDidFinishCompletion: { [weak self] _, isCompleted in 
        // ...
    }
)

In most cases, the SE-0279 syntax (and as reiterated in The Swift Programming Language, above) is generally preferable, as the functional intent of the first closure is generally pretty clear. In this case, though, the functional intent of the two closures is not entirely obvious, so perhaps being more explicit in labeling both closures (and not using the trailing closure syntax at all) may be warranted. Let the legibility of the resulting code dictate which pattern you adopt. But all things being equal, SE-0279 pattern, not labeling the first trailing closure, is the new convention.

But, either way, any of the above will avoid the SwiftLint error.

Rob
  • 415,655
  • 72
  • 787
  • 1,044