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*, not instancetype. means cannot inherited, because returns instance of wrong type. in subclass mybezierpath, calling bezierpathwithrect: 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

Popular posts from this blog

jquery - How do you format the date used in the popover widget title of FullCalendar? -

asp.net mvc - SSO between MVCForum and Umbraco7 -

Python Tkinter keyboard using bind -