You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中遵循继承协议的子类为何出现协议属性与方法默认实现不一致的异常?

Understanding the Quirky Protocol Extension Behavior in Your Swift Code

Let's break down exactly why you're seeing that confusing output when calling doSomething() on your LowerClass instance. It all boils down to how Swift handles static vs dynamic dispatch for protocol extensions, especially when combined with class inheritance.

First, Let's Recap the Behavior

  • lowerClass.level returns 1 (correct, matches LowerProtocol's default)
  • lowerClass.doSomething() outputs "Lower level is 10" (mix of LowerProtocol's method text and HigherProtocol's level value)

Why This Happens

1. How Property Access Works Here

When you directly access lowerClass.level, the compiler knows the static type of lowerClass is LowerClass, which conforms to LowerProtocol. Since LowerProtocol provides a more specific default for level than its parent HigherProtocol, the compiler statically binds this access to LowerProtocol's extension implementation, giving you 1 as expected.

2. How Method & Property Interaction Works in Protocol Extensions

The weirdness comes from the doSomething() method call:

  • Since neither LowerClass nor its parent HigherClass implement doSomething() themselves, the compiler statically binds the call to LowerProtocol's extension method (hence the "Lower level is" prefix).
  • Inside that method, when accessing level, self is treated as the LowerProtocol type (a protocol type, not a concrete class). For protocol types, property access uses dynamic dispatch.
  • Here's the catch: LowerClass doesn't have its own implementation of level—it's just using the default from LowerProtocol's extension. Protocol extension defaults don't get added to a class's vtable (the table used for dynamic dispatch). So when dynamically dispatching level, Swift falls back to the parent class HigherClass's implementation of level, which comes from HigherProtocol's extension (returning 10).

Fixing the Issue

To get the expected behavior, you need to explicitly implement level in LowerClass instead of relying solely on the protocol extension default. This adds the property to the class's vtable, ensuring dynamic dispatch works as intended:

class LowerClass: HigherClass, LowerProtocol {
    var level: Int { 1 }
}

Now, when doSomething() accesses level, dynamic dispatch will find LowerClass's implementation, and you'll get the output "Lower level is 1" as expected.

内容的提问来源于stack exchange,提问作者Kramer

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 05:17:45