带Self:UIView约束的Protocol为何引发Swift运行时崩溃?
where Self: UIView constraint cause a runtime crash in Swift Playground? The Problem
I wrote this code in Swift Playground:
import UIKit protocol Test where Self: UIView { func printAnything() } class MyView: UIView, Test { func printAnything() { print("Anything") } } let myView: Test = MyView() myView.printAnything()
When running this, I get a runtime error: error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=1, address=0x0). But if I remove the where Self: UIView constraint from the protocol, the code runs fine and prints "Anything". Why does this constraint cause a crash?
The Answer
Great question! Let's break down what's happening here and why the constraint triggers that crash:
Existential Types vs. Constrained Protocols
When you declarelet myView: Test = MyView(), you're usingTestas an existential type—meaning you're storing a concrete instance (MyView) in a variable typed to its protocol. For regular, unconstrained protocols, Swift's runtime handles this smoothly by creating a container that holds the instance and a "witness table" (a lookup table for protocol methods).But when you add
where Self: UIView, you're tying the protocol directly toSelfbeing a subclass ofUIView. This changes how the existential container is structured, and Swift's runtime struggles to resolve the method lookup correctly in this scenario.The Root of the Crash
When you callmyView.printAnything()on the existential type variable, the runtime tries to find the method implementation via the protocol's witness table. However, theSelf: UIViewconstraint confuses the runtime—it can't properly link the protocol's method to the concreteMyViewimplementation, leading to an attempt to access memory at address0x0(null pointer), hence theEXC_BAD_ACCESSerror.How to Fix It
You have two straightforward solutions to avoid this crash:- Use the concrete class type instead of the protocol:
let myView: MyView = MyView() myView.printAnything() // Runs fine - Use generics to leverage the protocol's abstraction:
If you need to keep the protocol's constraint and still work with abstract types, generics are the way to go—they resolve the type at compile time instead of relying on runtime existential handling:func processTestView<T: Test>(_ view: T) { view.printAnything() } let myView = MyView() processTestView(myView) // Works perfectly
- Use the concrete class type instead of the protocol:
This issue is particularly noticeable in Playgrounds because their runtime environment has subtle differences from a full iOS app, but the core problem stems from how Swift handles existential types with class-bound Self constraints.
内容的提问来源于stack exchange,提问作者J. Doe

