I am trying to subclass UICollectionViewLayoutAttributes
so that I can add an extra attribute points (an array of CGPoints
).
The subclass is designed to only be used as attributes for decoration views so I need to set the member representedElementCategory
to .Decoration
. But representedElementCategory
is readonly and the only way to set it is through the convenience initialiser:
convenience init(forDecorationViewOfKind decorationViewKind: String, withIndexPath indexPath: NSIndexPath)
Looking at the Objective-C headers I see this convenience initialiser is actually defined as a factory method:
+ (instancetype)layoutAttributesForDecorationViewOfKind:(NSString *)decorationViewKind withIndexPath:(NSIndexPath*)indexPath;
I would like my subclass' initialiser to look like:
CustomLayoutAttributes(points: [CGPoint], representedElementKind: String, withIndexPath: NSIndexPath)
But as subclasses aren't able to call the convenience initialisers of their parents I can't see how this would be possible.
Am I correct in thinking that the only way to subclass this is:
class CustomLayoutAttributes: UICollectionViewLayoutAttributes {
var points = [CGPoint]()
}
let attribs = UICollectionViewLayoutAttributes(
forDecorationViewOfKind: "x",
withIndexPath: NSIndexPath(forItem: 0, inSection: 0)
) as! CustomLayoutAttributes
attribs.points = [CGPoint(x: 1.0, y: 2.0), CGPoint(x: 4.0, y: 5.0)]
Actually this won't work because the 'as!' cast will fail....
It turns out that a sub class can call a super class' convenience initialiser which can in turn call the sub class' initialiser. For example:
CustomLayoutAttributes(forDecorationViewOfKind: "decoration1", withIndexPath: indexPath)
Here:
init(forDecorationViewOfKind: String, withIndexPath: NSIndexPath)
isn't defined in the CustomLayoutAttributes
class but can still be used to construct an instance of the subclass.
Implementation example:
// CustomLayoutAttributes.swift
class CustomLayoutAttributes: UICollectionViewLayoutAttributes {
// Additional attribute to test our custom layout
var points = [CGPoint]()
// MARK: NSCopying
override func copyWithZone(zone: NSZone) -> AnyObject {
let copy = super.copyWithZone(zone) as! CustomLayoutAttributes
copy.points = self.points
return copy
}
override func isEqual(object: AnyObject?) -> Bool {
if let rhs = object as? CustomLayoutAttributes {
if points != rhs.points {
return false
}
return super.isEqual(object)
} else {
return false
}
}
}
// CustomLayout.swift
override func layoutAttributesForItemAtIndexPath(path: NSIndexPath) -> UICollectionViewLayoutAttributes? {
let attributes = CustomLayoutAttributes(forDecorationViewOfKind: "decoration1", withIndexPath: indexPath)
attributes.points = [...]
return attributes
}