使用通用协议筛选子视图数组



在我们的应用程序中,我们有一个画布。画布可以包含贴纸、图像、文本等。我们有一个协议CanvasItem,用于实现这些项目之间的公共属性:

protocol CanvasItemProtocol{
var scale : CGFloat { get set }
}
class CanvasItem : CanvasItemProtocol {
public var scale : CGFloat = 1.0
}

然后每个类模型(贴纸、文本等(都符合CanvasItem,添加特定于类的属性:

public class StickerItem: CanvasItem {
public var stickerName: String
}
public class ShapeItem: CanvasItem {
public var shapeColor: UIColor
}

为了展示这些,我们首先创建了一个基本的泛型(我认为(UIView类,它只能通过CanvasItem启动:

class ViewItem <T: CanvasItemProtocol>: UIView {
let canvasItem: T
init (t: T) {
self.canvasItem = t
super .init(frame: .zero)
}
}

然后对于每个模型,我们创建特定的UIView<CanvasItem>类:

class CanvasShapeView: ViewClass<ShapeItem> { }
class CanvasStickerView: ViewClass<StickerItem> { }

然后我尝试执行以下操作:

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**
}

它编译,但返回零结果(强制转换不起作用(... 我尝试仅访问CanvasItem公共属性

要点链接: 游乐场.swift

有什么建议吗?我们已经坚持了几天了。

任何帮助将不胜感激。

协议和泛型与子类化不能很好地协同工作

实际上,您既不需要协议也不需要视图包装器类。 子类化UIView就足够了。

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)
}

CanvasShapeViewCanvasStickerView共享类的模板,但它们是完全不同的类。

这就是为什么我会检查类是否符合相同的模板 - 搜索canvasItem作为类的一部分,然后尝试获取所需的值:

let test = superview.subviews
.compactMap({ Mirror(reflecting: $0).children.first(where: { $0.label == "canvasItem" }) })
.compactMap({ $0.value as? CanvasItemProtocol })
for value in test {
print(value.scale)
}

我不得不使用反射来做到这一点 - 我想这不是最好的解决方案,但它做到了。

最新更新