Andriy Gordiychuk
Andriy Gordiychuk

Reputation: 6272

Subclass in Swift does not inherit initialiser of its superclass

I have stumbled upon a very strange issue when trying to subclass NSBezierPath.

Below is the definition of my subclass:

class OSBezierPath: NSBezierPath {
        
    func addLineToPoint(point:CGPoint) {
        self.lineToPoint(point)
    }
}

This subclass works apart from the fact that I cannot access some of the initialisers of the NSBezierPath. For example, line below is invalid:

let path = OSBezierPath(ovalInRect: rect)

Compiler throws an error

Extra argument 'ovalInRect' in call

Cause of this bug

Cause of this bug is well-explained in another question. However, the suggested answer doesn't work well for me because what I am trying to achieve is to use OSBezierPath on both iOS and Mac OS.

My original code read like this:

#if os(iOS)
    typealias OSBezierPath = UIBezierPath
#else
    class OSBezierPath: NSBezierPath {
        
        func addLineToPoint(point:CGPoint) {
            self.lineToPoint(point)
        }
    }
#endif

This code doesn't work, but I have found 2 workarounds which are more elegant for my purpose than the suggested answer in another question.

Upvotes: 0

Views: 444

Answers (1)

Andriy Gordiychuk
Andriy Gordiychuk

Reputation: 6272

1st solution

This solution uses extension to add a function to NSBezierPath which will allow it to draw lines in the same way as UIBezierPath.

#if os(iOS)
    typealias OSBezierPath = UIBezierPath
#else
    typealias OSBezierPath = NSBezierPath
    
    extension OSBezierPath {
        func addLineToPoint(point:CGPoint) {
            self.lineToPoint(point)
        }
    }
#endif

This avoids any potential bug because there is no subclassing involved. Therefore, line below:

let path = OSBezierPath(ovalInRect: rect)

actually translates to:

let path = NSBezierPath(ovalInRect: rect)

and so compiler is happy :)

2nd solution (Xcode 7)

Second solution uses the fact that class functions of UIBezierPath were converted to proper initialisers in Xcode 7. So, code below will work:

#if os(iOS)
    class OSBezierPath: UIBezierPath {
        func lineToPoint(point:CGPoint) {
            self.addLineToPoint(point)
        }
    }
#else
    typealias OSBezierPath = NSBezierPath
#endif

This allows us to use OSBezierPath by calling lineToPoint on both iOS and Mac OS.

Upvotes: 3

Related Questions