I am trying to set a property called activeTableViewCell
declared as;
var activeTableViewCell: UITableViewCell?
using a switch statement in my cellForRowAt
delegate method which sets the property to one of two possible values depending upon another property called deviceOrientation
;
switch deviceOrientation {
case .portrait:
activeTableViewCell = tableView.dequeueReusableCell(withIdentifier: "CompanyStockCell", for: indexPath) as! CompanyStockCellPortrait
case .landscape:
activeTableViewCell = tableView.dequeueReusableCell(withIdentifier: "CompanyStockCell", for: indexPath) as! CompanyStockCellLandscape
}
but Xcode reports an error on the next line of code;
activeTableViewCell.symbolValue.text = companyStockInfo[indexPath.row].symbol
with the error message;
Value of type 'UITableViewCell?' has no member named 'symbolValue'
symbolValue
is a stored property of CompanyStockCellPortrait
and CompanyStockCellLandscape
both of which are subclasses of UITableViewCell
.
How can I get this to work?
CodePudding user response:
You can use a base class to hold to common properties, and derive the two other classes from it:
class CompanyStockCell: UITableViewCell {
var symbolValue: UILabel
// other common stuff
}
class CompanyStockCellPortrait: CompanyStockCell {
// specific portrait stuff
}
class CompanyStockCellLandscape: CompanyStockCell {
// specific landscape stuff
}
CodePudding user response:
I would recommend that you apply DRY principles, and that you consider eliminating the two separate classes, altogether.
Have a single class. If you want to have different layouts for device orientations, then implement unique constraints contingent upon the appropriate orientation using size classes.
Consider my example below, where each table row has two subviews, a red one and a blue one. Let us assume that in landscape orientation, there is room to see one next to the other, but in portrait orientation, you have to put the second one below the first. You can handle this all with a single cell class, but just customize which constraints are employed in each device orientation (i.e., each horizontal size class).
In this scenario, let us consider just one particular constraint, the “should the tops of the two views be aligned.” In the highlighted part of the Xcode screen snapshot, I show that the constraint is not installed in a horizontal compact size class (i.e., portrait), but is in regular size class (i.e., landscape):
You can just repeat that process for each of the constraints that vary by size class.
This has several advantages:
You then end up with a single cell class. It is less code, less duplicative code, and completely eliminates your question of how to reference the same property in two different classes;
Enjoy a unique layout for each size class (i.e., orientation); and
The animation is more elegant, not requiring a redraw of the whole view, but animates the views into the right places, without having to reload the table view on rotation events:
If you cannot do this for some reason, you have a few other alternatives:
- have a single cell class, two different NIBs or storyboard prototype cells that use this same, single cell class for both; or
- have the two cell classes, but a protocol to define the common property between two classes.
I think the single cell class with custom size class constraints is the best, but if your two cells have significantly different code implementations, too, then you can fall back to one of these other two, older, patterns.
I must confess that this size class approach takes a few tries to get comfortable with it, so you might experiment with some simple examples before you attempt refactoring your existing codebase.