ios - UIBezierPath Subclass Initializer -
i'm trying create subclass of uibezierpath add properties useful me.
class myuibezierpath : uibezierpath { var selectedforlazo : bool! = false override init(){ super.init() } /* compile error: must call designated initializer of superclass 'uibezierpath' */ init(rect: cgrect){ super.init(rect: rect) } /* compile error: must call designated initializer of superclass 'uibezierpath' */ init(roundedrect: cgrect, cornerradius: cgfloat) { super.init(roundedrect: roundedrect, cornerradius: cornerradius) } required init(coder adecoder: nscoder) { fatalerror("init(coder:) has not been implemented") } }
edit: need because in code write
var path = myuibezierpath(roundedrect: rect, cornerradius: 7)
and results in compile error:
"must call designated initializer of superclass 'uibezierpath'"
i tried add initializers in subclass seems not work.
can me please?
note: problem solved in ios 9, api has been rewritten init(rect:)
exists, , others, convenience initializers, should be.
the problem
in nutshell, problem you're experiencing following code not compile:
class mybezierpath : uibezierpath {} let b = mybezierpath(rect:cgrectzero)
from swift point of view, seems wrong. documentation appears uibezierpath has initializer init(rect:)
. why isn't uibezierpath's init(rect:)
being inherited in our subclass mybezierpath? according normal rules of initializer inheritance, should be.
the explanation
uibezierpath not intended subclassing. accordingly, doesn't have initializers - except init()
, inherits nsobject. in swift, uibezierpath looks if has initializers; false representation. uibezierpath has, can see if @ objective-c headers, convenience constructors, class methods, such this:
+ (uibezierpath *)bezierpathwithrect:(cgrect)rect;
now, method (along siblings) demonstrates unusual features swift not deal well:
it not merely variant of initializer; pure convenience constructor. objective-c shows uibezierpath has no corresponding true initializer
initwithrect:
. that's unusual situation in cocoa.it returns
uibezierpath*
, notinstancetype
. means cannot inherited, because returns instance of wrong type. in subclass mybezierpath, callingbezierpathwithrect:
yields uibezierpath, not mybezierpath.
swift copes badly situation. on 1 hand, translates class method bezierpathwithrect:
apparent initializer init(rect:)
, in accordance usual policy. on other hand, not "real" initializer, , cannot inherited subclass.
you have been misled apparent initializer init(rect:)
, surprised , stumped when not call on subclass because isn't inherited.
note: i'm not saying swift's behavior here not bug; think is bug (though i'm little hazy on whether blame bug on swift or on uibezierpath api). either swift should not turn bezierpathwithrect:
initializer, or, if does make initializer, should make initializer inheritable. either way, should inheritable. isn't, have workaround.
solutions
so should do? have 2 solutions:
don't subclass. subclassing uibezierpath bad idea start with. not made sort of thing. instead of subclass, make wrapper - class or struct that, rather having feature is uibezierpath, has feature has uibezierpath. let's call mybezierpathwrapper:
struct mybezierpathwrapper { var selectedforlazo : bool = false var bezierpath : uibezierpath! }
this couples custom properties , methods normal uibezierpath. create in 2 steps, this:
var b = mybezierpathwrapper() b.bezierpath = uibezierpath(rect:cgrectzero)
if feels unsatisfactory, can make one-step creation adding initializer takes uibezierpath:
struct mybezierpathwrapper { var selectedforlazo : bool = false var bezierpath : uibezierpath init(_ bezierpath:uibezierpath) { self.bezierpath = bezierpath } }
and can create this:
var b = mybezierpathwrapper(uibezierpath(rect:cgrectzero))
subclass convenience constructor. if insist on subclassing, though uibezierpath not intended sort of thing, can supplying convenience constructor. works because important thing uibezierpath
cgpath
, can make convenience constructor copy constructor merely transferring path real uibezierpath:class mybezierpath : uibezierpath { var selectedforlazo : bool! = false convenience init(path:uibezierpath) { self.init() self.cgpath = path.cgpath } }
now can create 1 previous approach:
let b = mybezierpath(path:uibezierpath(rect:cgrectzero))
it isn't great, think it's marginally more satisfying having redefine all initializers solution does. in end i'm doing same thing you're doing, in more compressed way. on balance prefer first solution: don't subclass in first place.
Comments
Post a Comment