extension ActionSheetViewController: UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sheetActions.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: TableCellIds.ActionSheet.actionSheetTableCellIdentifier, for: indexPath) as! ActionsSheetCell
cell.actionCellLabel.text = "My cell content goes here"
return cell
}
}
Above code gives me ‘Force Cast Violation: Force casts should be avoided. (force_cast)‘ error. How can I avoid it?
4
Answers
Some force-casts are unavoidable, especially when interacting with Objective C, which has a much more dynamic/loose type system.
In some cases like this, a force-cast would be self-explanatory. If it crashes, clearly you’re either:
nil
(meaning there’s no view with that reuse identifier),In either case your app is critically mis-configured, and there’s no much graceful recovery you can do besides fixing the bug in the first place.
For this particular context, I use a helper extension like this (it’s for AppKit, but it’s easy enough to adapt). It checks for the two conditions above, and renders more helpful error messages.
Honestly, after I got experienced enough with the
NSTableView
APIs, investigating these issues became second nature, and I don’t find this extension as useful. Still, it could save some debugging and frustration for devs who are new the platform.The force cast is actually correct in this situation.
The point here is that you really don’t want to proceed if you can’t do the cast, because you must return a real cell and if it’s the wrong class, the app is broken and you have no cell, so crashing is fine.
But the linter doesn’t realize that. The usual way to get this past the linter is to do a
guard let
withas?
, along with afatalError
in theelse
. That has the same effect, and the linter will buy into it.I really like the approach suggested by Alexander at https://stackoverflow.com/a/67222587/341994 – here’s an iOS modification of it:
So now you can say e.g.:
And everyone is happy including the linter. No forced unwraps anywhere and the cast is performed automatically thanks to the generic and the explicit type declaration.
As others have said, a force cast is appropriate in this case, because if it fails, it means you have a critical error in your source code.
To make SwiftLint accept the cast, you can surround the statement with comments as described in this issue in the SwiftLint repo:
The right thing to do is: remove force_cast from swift lint’s configuration file. And be professional: only write force casts where you mean “unwrap or fatal error”. Having to “get around the linter” is a pointless waste of developer time.