为何switch case无法捕获UIButton的.systemBrown UIColor?
UIColor Switch分支匹配异常问题解析
问题场景
编写了如下用于根据背景色返回对应文本色的函数:
func getColor(_ background: UIColor) -> UIColor { switch background { case .white, .systemBrown: return .black case .darkGray: return .lightGray case .black: return .white default: return .label } }
同时创建了背景色为.systemBrown的UIButton:
let brownButton: UIButton = { let btn = UIButton() btn.translatesAutoresizingMaskIntoConstraints = false btn.backgroundColor = .systemBrown btn.layer.borderWidth = 1.0 btn.layer.borderColor = UIColor.brown.cgColor return btn }()
出现的异常现象:
- 直接调用
getColor(.systemBrown)时,返回预期的.black - 调用
getColor(brownButton.backgroundColor!)时,却进入default分支返回.label
原因分析
这是因为UIColor实例的引用相等性不等于颜色值相等性:
.systemBrown属于动态颜色(Dynamic Color),这类颜色会根据当前的 trait collection(比如亮色/暗色模式)解析出实际的颜色值。- 当你将
.systemBrown赋值给UIButton的backgroundColor后,UIKit会自动根据当前环境解析该动态颜色,返回一个经过解析的UIColor实例——这个实例和你直接调用的.systemBrown不是同一个对象。 - Swift的switch case对UIColor的匹配依赖于
==运算符,而UIColor的默认==比较的是实例引用,不是颜色的实际RGB值。因此解析后的实例无法匹配到case里的.systemBrown,只能走到default分支。
解决方案
如果需要根据颜色的实际值进行判断,不要依赖实例引用匹配,而是比较颜色的实际解析值:
- 通过
resolvedColor(with:)获取当前环境下的解析颜色,再比较其cgColor:
func getColor(_ background: UIColor) -> UIColor { let resolvedBg = background.resolvedColor(with: UITraitCollection.current) let systemBrownResolved = UIColor.systemBrown.resolvedColor(with: UITraitCollection.current) switch resolvedBg.cgColor { case UIColor.white.cgColor, systemBrownResolved.cgColor: return .black case UIColor.darkGray.cgColor: return .lightGray case UIColor.black.cgColor: return .white default: return .label } }
- 或者直接提取颜色的RGB组件进行比较(适用于非动态颜色或已解析的颜色)。
内容的提问来源于stack exchange,提问作者Enkidu
相关产品推荐
相关产品推荐

