cast viewWithTag result as UILabel ?

Hi,


In a UITableViewCell class I want to find a UILabel subview using a tag, but am struggling to understand the safest/cleanest way to do it. This has the correct result, but doesn't feel it's the best way.


guard let returnedView = tableCell.contentView.viewWithTag(99) else {
    return cell
}
let labelView = returnedView as! UILabel
labelView.text = "my text"


Alternatively I can do this, but is this 'safe'? What happens if viewWithTag returns nil, is the forced downcast ignored? I assume the downcast is only acted upon if viewWithTag returns something to downcast (and is true in the wider sense). But in that case, would the labelView (line 02) setting of text just be ignored also?


let labelView = (tableCell.contentView.viewWithTag(99)) as! UILabel
labelView.text = "my text"


thanks,

Accepted Reply

As OOPer pointed out, as! is pretty risky here ; if your view is not a label, you crash.


In addition, if you have given the same tag to 2 elements, what will occur ?


So, definetely, it is better to create a label99 property.


But, if you want to keep this code:

What happens if viewWithTag returns nil ?

-> you return the function, so you ignore all the following


To make it safer :

if let _ = returnedView as? UILabel { // just check it is a label
     returnedView.text = "my text"
}

Replies

The safest/cleanest way would be to define your own subclass of UITableViewCell which has a property named `label99` of type `UILabel`.

Generally, if your code has some sort of searching for view hierarchy, you should better think that is dirty and unsafe.


And your usage of `as!` cannot be safe by any means. You should better avoid using `as!`.

As OOPer pointed out, as! is pretty risky here ; if your view is not a label, you crash.


In addition, if you have given the same tag to 2 elements, what will occur ?


So, definetely, it is better to create a label99 property.


But, if you want to keep this code:

What happens if viewWithTag returns nil ?

-> you return the function, so you ignore all the following


To make it safer :

if let _ = returnedView as? UILabel { // just check it is a label
     returnedView.text = "my text"
}

The safest, most concise way is probably:


guard let returnedView = tableCell.contentView.viewWithTag(99), let labelView = returnedView as? UILabel else {  
    return cell  
}  
labelView.text = "my text"

This code snippet is what I was missing I think. It's quite easy to get tied up in Xcode knots, when it offers to 'fix' things with ! and then fix that with ?


I was trying to create a bunch of UIView's in a function of the subclassed cell. Adding properties there quickly felt not-great. What I will do is maybe subclass the UIView I am creating, which can then have its own properties. And the cell class just instantiates from that UIView subclass.


But in the wider, Swift, understanding, if I'm setting something if it exists, the 'if let _' is the cleanest for me.


thanks for your help guys.