Search code examples
swiftcastingextension-methodsexc-bad-accessswift-protocols

Swift - Inheriting protocol does not inherit generic where constraint


I am trying to migrate to using protocols instead of subclassing, but I still would like to be able to delegate up to the "super" implementation of a certain method before performing more specific logic. Below is the code I've written to demonstrate the functionality I want, but it's crashing. If this is for some reason a bad approach/missing the point of protocol oriented programming then I would love to learn why, but also right now I just need to know why this is crashing. Thanks!

import UIKit

protocol A where Self: UIView { }
extension A {
  func method () {
    print("protocol A")
  }
}

protocol B: A { }
extension B {
  func method () {
    print("protocol B")
    (self as A).method()
  }
}

class X: UIView, B {
  func method () {
    print("class X")
    (self as B).method()
  }
}

This code is invoked simply by doing this:

let x = X()
x.method()

The code above crashes with an EXC_BAD_ACCESS at this line:

(self as A).method()

Solution

  • I have a partial answer, even though I still do not understand exactly what is going. I noticed that this crash was only occurring when I had the

    where Self: UIView 
    

    constraint on protocol A. If I remove the constraint, no crash occurs. This made me think that somehow the object is losing its status as a UIView somewhere along the way, and that this is the problem. More specifically, it seems that when protocol B inherits from protocol A, it does not inherit the

    where Self: UIView
    

    clause, meaning that casting to B does not imply that the resulting entity is a UIView. Following this line of thinking, I was able to make the above code work by changing:

    (self as B).method()
    

    to

    (self as B & UIView).method()
    

    This seems like a bug to me, so I'm going to try to bring it to the attention of the Swift team.