In our app, we have a canvas. The canvas could contain Stickers, Images, Texts, etc. We have a protocol CanvasItem
that implement the common properties between these items:
protocol CanvasItemProtocol{
var scale : CGFloat { get set }
}
class CanvasItem : CanvasItemProtocol {
public var scale : CGFloat = 1.0
}
Then each class-model (Stickers, Text etc) conform to CanvasItem
, adding class-specific properties:
public class StickerItem: CanvasItem {
public var stickerName: String
}
public class ShapeItem: CanvasItem {
public var shapeColor: UIColor
}
To show those, we first created a base generic (I think) UIView
class that can be inited only with CanvasItem
:
class ViewItem <T: CanvasItemProtocol>: UIView {
let canvasItem: T
init (t: T) {
self.canvasItem = t
super .init(frame: .zero)
}
}
and then for each of the models, we create specific UIView<CanvasItem>
class:
class CanvasShapeView: ViewClass<ShapeItem> { }
class CanvasStickerView: ViewClass<StickerItem> { }
Then I'm trying to do the following:
let superview = UIView()
let shapeView = CanvasStickerView(StickerItem())
let stickerView = CanvasShapeView(ShapeItem())
superview.addSubview(shapeView)
superview.addSubview(stickerView)
for canvasItemView in superview.subviews.compactMap({$0 as? ViewItem<CanvasItem>}) {
print(canvasItemView.canvasItem.scale) // **access only the common properties**
}
It compiles, but return zero results (the casting not working)...
I'm trying to access only to the CanvasItem
common properties.
Gist link: Playground.swift
Any suggestions? We stuck on this for a few good days now.
Any help would be highly appreciated.
Protocols and generics in conjunction with subclassing don't work together very well
Actually you don't need neither the protocol nor the view wrapper class. Subclassing UIView
is sufficient.
class CanvasItem : UIView
{
public var scale : CGFloat = 1.0
}
class StickerItem: CanvasItem
{
public var stickerName : String = ""
}
class ShapeItem: CanvasItem
{
public var color: UIColor = .red
}
let shapeItem = ShapeItem()
let stickerItem = StickerItem()
let superview = UIView()
superview.addSubview(shapeItem)
superview.addSubview(stickerItem)
for case let canvasItemView as CanvasItem in superview.subviews {
print(canvasItemView.scale)
}