Is Force Cast Really Bad and Should Always Avoid It

Is force cast really bad and should always avoid it?

This question is probably opinion based, so take my answer with a grain of salt, but I wouldn't say that force downcast is always bad; you just need to consider the semantics and how that applies in a given situation.

as! SomeClass is a contract, it basically says "I guarantee that this thing is an instance of SomeClass". If it turns out that it isn't SomeClass then an exception will be thrown because you violated the contract.

You need to consider the context in which you are using this contract and what appropriate action you could take if you didn't use the force downcast.

In the example you give, if dequeueReusableCellWithIdentifier doesn't give you a MyOffersViewCell then you have probably misconfigured something to do with the cell reuse identifier and an exception will help you find that issue.

If you used a conditional downcast then you are going to get nil and have to handle that somehow - Log a message? Throw an exception? It certainly represents an unrecoverable error and something that you want to find during development; you wouldn't expect to have to handle this after release. Your code isn't going to suddenly start returning different types of cells. If you just let the code crash on the force downcast it will point straight to the line where the issue occurred.

Now, consider a case where you are accessing some JSON retrieved from a web service. There could be a change in the web service that is beyond your control so handling this more gracefully might be nice. Your app may not be able to function but at least you can show an alert rather than simply crashing:

BAD - Crashes if JSON isn't an array

 let someArray=myJSON as! NSArray 
...

Better - Handle invalid JSON with an alert

guard let someArray=myJSON as? NSArray else {
// Display a UIAlertController telling the user to check for an updated app..
return
}

How to correct avoid this force cast

Don't avoid it, do the force cast.

That's one of the rare cases where a force cast is welcome.

The code must not crash if everything is hooked up correctly. If it does it reveals a design mistake.

Avoiding the force cast with optional binding is pointless because in case of the mentioned design mistake the table view will display nothing.

SecIdentity + Force Cast Violation: Force casts should be avoided. (force_cast)

Basically, what you're doing is a force downcast, meaning that you guarantee that yours identityPointer and trustPointer are objects of SecIdentity and SecTrust classes respectively. But what if they are not? You take them out of the dictionary as AnyObject, so generally they may not cast to the target classes. Swiftlint tells you, that force casting is a bad practise and wants you to avoid it.

However, it seems with CoreFoundation type you can't use a conditional cast as?, so force cast is your only choice. For this particular case you can disable Swiftlint rule in code adding a special comment.

let secIdentityRef = identityPointer as! SecIdentity // swiftlint:disable:this force_cast

To be on the safe side, you also may check the identity of the object by checking the Core Foundation "type id":

guard let identityPointer = certEntry["identity"],
CFGetTypeID(identityPointer) == SecIdentityGetTypeID() else {
// here you know that the cast will fail
}
let secIdentityRef = identityPointer as! SecIdentity // swiftlint:disable:this force_cast

Should conditional binding be used always for dequeuing cell

UITableView has two dequeue modes:

  1. dequeueReusableCell(withIdentifier:): The table view tries to dequeue a cell. If there are none, it will try to create one using the cell you registered with the reuseIdentifier. If you didn't register a cell, it will return nil giving you the chance to create one yourself.

This is where the else clause in your code would come into effect. Basically never, since presumably you did register a cell class. Most likely in the Storyboard (by setting the identifier in the inspector) but you can also do it in code.


  1. dequeueReusableCell(withIdentifier:for:), note the additional parameter. The table view tries to dequeue a cell: If there are none, it will try to create one using the cell class you registered using the reuseIdentifier. If you didn't register a cell, it will crash.

Solution

If you can guarantee that a) the cell is correctly registered and b) the type of the cell is set correctly, you would generally use the second option. This avoids the exact issue you're having:

let cell = tableView.dequeueReusableCellWithIdentifier("myCustomCell", forIndexPath: indexPath) as! myCustomCell

(However, it is still perfectly fine to use if let even in this case.)

Can 'downcasting' to AppDelegate ever fail?

Optional downcasting to AppDelegate (actually to the class representing the application delegate class) will never fail because the application won't even launch if the application delegate class was missing.

You can 100% safely write

let appDelegate = UIApplication.shared.delegate as! AppDelegate

Many people suffer from exclamationmarkophobia and argue that all exclamation marks are evil and you always have to guard any optional. This is wrong. The world is not only black and white. There are many cases where forced unwrapping an optional is safe like in this particular case.

Need some clarification regarding casting in C

There are several situations that require perfectly valid casting in C. Beware of sweeping assertions like "casting is always bad design", since they are obviously and patently bogus.

One huge group of situations that critically relies on casts is arithmetic operations. The casting is required in situations when you need to force the compiler to interpret arithmetic expression within a type different from the "default" one. As in

unsigned i = ...;
unsigned long s = (unsigned long) i * i;

to avoid overflow. Or in

double d = (double) i / 5;

in order to make the compiler to switch to floating-point division. Or in

s = (unsigned) d * 3 + i;

in order to take the whole part of the floating point value. And so on (the examples are endless).

Another group of valid uses is idioms, i.e. well-established coding practices. For example, the classic C idiom when a function takes a const pointer as an input and returns a non-const pointer to the same (potentially constant) data, like the standard strstr for example. Implementing this idiom usually requires a use of a cast in order to cast away the constness of the input. Someone might call it bad design, but in reality there's no better design alternative in C. Otherwise, it wouldn't be a well-established idiom :)

Also it is worth mentioning, as an example, that a pedantically correct use of standard printf function might require casts on the arguments in general case. (Like %p format specifier expecting a void * pointer as an argument, which means that an int * argument has to be transformed into a void * in one way or another. An explicit cast is the most logical way to perform the transformation.).

Of course, there are other numerous examples of perfectly valid situations when casts are required.

The problems with casts usually arise when people use them thoughtlessly, even where they are not required (like casting the return of malloc, which is bad for more reasons than one). Or when people use casts to force the compiler to accept their bad code. Needless to say, it takes certain level of expertise to tell a valid cast situation from a bad cast one.

In some cases casts are used to make the compiler to stop issuing some annoying and unnecessary warning messages. These casts belong to the gray area between the good and the bad casts. On the one hand, unnecessary casts are bad. On the other hand, the user might not have control over the compilation settings, thus making the casts the only way to deal with the warnings.

Avoid casting in inherited java-classes

You can use the self-type pattern:

class MyClass<T extends MyClass<T>> { 
public T getParent() { ... }
public List<T> getChildren() { ... } // you can use an array here too, but don't :)
}

class MySubclass extends MyClass<MySubclass> {
public String getId() { ... }
}

You can implement your getParent and getChildren methods as desired, declare fields in MyClass that hold T references and know that they behave at least as MyClass references, et cetera. And if you call getParent or getChildren on a MySubClass, you can use the return values as MySubClass instances with no casts anywhere.

The primary disadvantage of this approach is that people who haven't seen it before tend to get pretty confused.

UICollectionViewCells deque returns wrong cell

That's how collectionView.dequeueReusableCellWithReuseIdentifier works.
If you want to go around this functionality you could save all cells that are created in an array and then instead of dequeueing you could fetch the one with the video already loaded. However, if you use some framework that caches the videos after loading them you shouldn't need to deal with this at all.

var cells: [CustomCollectionViewCell] = []

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
var cell:CustomCollectionViewCell?
if cells.count >= indexPath.row {
cell = cells[indexPath.row]
} else {
cell = CustomCollectionViewCell()
//setup cell
cells.append(cell)
}

return cell!
}

Disclaimer:

This solution is a hack. As mentioned by @Async in the comment below this solution will use a lot of memory if you create a lot of cells.



Related Topics



Leave a reply



Submit