英文:
Swift: "any generic" in function causes "_ErrorCodeProtocol has no member" error
问题
Swift 5.8 使用 'any generic' 导致奇怪的错误 (_ErrorCodeProtocol)
你好!在我的宠物项目中,我想要减少 UIKit 的布局代码(我使用程序化的 UI 布局)。我的想法是为我的宠物项目创建一个用于最常见情况的枚举,例如:
// view 是一个视图控制器的视图
let searchArea = UIView()
view.addSubview(searchArea)
searchArea.applyConstraints(
.alignTopWithTop(of: guide),
.alignLeadingWithLeading(of: view),
.alignTrailingWithTrailing(of: view),
.alignHeight(with: view, mult: 0.1)
)
我真的很喜欢它,比起下面的方式更好:
let searchArea = UIView()
view.addSubview(searchArea)
object.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
searchArea.topAnchor.constraint(equalTo: view.topAnchor, constant: 0),
searchArea.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
searchArea.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
searchArea.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1, constant: 0)
])
因为 UIViews 应该与其他 UIView 子视图以及 UIViewController 安全区域 (UILayoutGuide) 对齐,我使用了泛型来实现这一点:
protocol UISnapable {
var leadingAnchor: NSLayoutXAxisAnchor { get }
// 这里包括 UIView 和 UILayoutGuide 同时拥有的其他锚点
var centerYAnchor: NSLayoutYAxisAnchor { get }
}
extension UIView: UISnapable {}
extension UILayoutGuide: UISnapable {}
enum Constraints<T: UISnapable> {
case alignTopWithTop(of: T, const: CGFloat = 0)
// 还有其他对齐情况
case setAspectWidth(ratio: CGFloat)
}
func applyConstraints(object: inout UIView, constraints: any UISnapable...) {
object.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate(
// 将输入的可变参数转换为约束
constraints.map {
switch $0 {
case .alignTopWithTop(of: let of, const: let const):
return object.topAnchor.constraint(
equalTo: of.topAnchor,
constant: const
)
// 其他对齐情况
case .setAspectWidth(ratio: let ratio):
return object.heightAnchor.constraint(
equalTo: object.widthAnchor,
multiplier: ratio
)
}
}
)
}
我在泛型 UISnapable 中使用了 "any" 关键字,因为它最近在 Swift 中为这种情况引入了。
但不幸的是,我遇到了错误 "Type _ErrorCodeProtocol has no member alignTopWithTop"。
我做错了什么?我不知道 _ErrorCodeProtocol 如何与我的泛型情况相关联。
我检查了 _ErrorCodeProtocol 的源代码,它指向 Foundation。但我没有在 Foundation 中找到它的声明。而且在 Apple 文档中也没有关于它的信息(https://developer.apple.com/search/?q=_ErrorCodeProtocol&type=Documentation)。
英文:
Swift 5.8 using 'any generic' causes strange error (_ErrorCodeProtocol)
Hello! In my Pet project I want to reduce layout code for UIKit (I'm using programmatic UI layout). The idea is to make enum for most used cases in my pet like:
// view is a view controller's view
let searchArea = UIView()
view.addSubview(searchArea)
searchArea.applyConstraints(
.alignTopWithTop(of: guide),
.alignLeadingWithLeading(of: view),
.alignTrailingWithTrailing(of: view),
.alignHeight(with: view, mult: 0.1)
)
I really like it much more than:
let searchArea = UIView()
view.addSubview(searchArea)
object.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
searchArea.topAnchor.constraint(equalTo: view.topAnchor, constant: 0),
searchArea.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
searchArea.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
searchArea.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1, constant: 0)
])
Because UIViews should be aligned to other UIView childs as well as UIViewController safe Area (UILayoutGuide) I implemented this using generics:
protocol UISnapable {
var leadingAnchor: NSLayoutXAxisAnchor { get }
// Here are other anchors that UIView and UILayoutGuide have at the same time
var centerYAnchor: NSLayoutYAxisAnchor { get }
}
extension UIView: UISnapable {}
extension UILayoutGuide: UISnapable {}
enum Constraints<T: UISnapable> {
case alignTopWithTop(of: T, const: CGFloat = 0)
// Other align cases here
case setAspectWidth(ratio: CGFloat)
}
func applyConstraints(object: inout UIView, constraints: any UISnapable...) {
object.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate(
// Transforming input variadic to constraints
constraints.map {
switch $0 {
case .alignTopWithTop(of: let of, const: let const):
return object.topAnchor.constraint(
equalTo: of.topAnchor,
constant: const
)
// Other align cases here
case .setAspectWidth(ratio: let ratio):
return object.heightAnchor.constraint(
equalTo: object.widthAnchor,
multiplier: ratio
)
}
}
)
}
I use "any" keyword for generic UISnapable as it's was recently introduced in Swift for such cases.
But unfortunately, I get error "Type _ErrorCodeProtocol has no member alignTopWithTop"
What I am doing wrong? I dunno how _ErrorCodeProtocol is connected to my generic case.
I've checked source of _ErrorCodeProtocol and it lead to Foundation. But I didn't find its declaration somewhere in foundation. Also I didn't find information on it in Apple docs (https://developer.apple.com/search/?q=_ErrorCodeProtocol&type=Documentation)
答案1
得分: 1
你传递的是UISnapable列表,但你的意思是传递Constraints列表。在这种情况下,你将any
放在了错误的位置。
我认为你的意思是这样的:
// Constraints不是泛型,但在某些情况下可以容纳任何UISnapable
enum Constraints {
// 使用`any UISnapable`而不是T
case alignTopWithTop(of: any UISnapable, const: CGFloat = 0)
// 在这里添加其他对齐情况
case setAspectWidth(ratio: CGFloat)
}
然后方法是(请注意,这里的inout
是不必要的;UIView是一个引用类型):
func applyConstraints(object: inout UIView, constraints: Constraints...) {
^^^^^^^^^^^
至于错误,编译器之所以困惑,是因为你正尝试switch
一个非枚举类型(这里的$0
是any UISnapable
)。这个错误并不特别有帮助,并且与潜在问题无关。
英文:
You're passing a list of UISnapable, but you mean to pass a list of Constraints. In this case you're putting any
in the wrong place.
What I believe you mean is this:
// Constraints are not generic, but they can hold any UISnapable in some cases
enum Constraints {
// Use `any UISnapable` rather than T
case alignTopWithTop(of: any UISnapable, const: CGFloat = 0)
// Other align cases here
case setAspectWidth(ratio: CGFloat)
}
And then the method is (note that the inout
here is unnecessary; UIView is a reference type):
func applyConstraints(object: inout UIView, constraints: Constraints...) {
^^^^^^^^^^^
As for the error, the compiler is just getting confused because you're trying to switch
on a non-enum ($0
here is any UISnapable
). The error is not particularly helpful, and is not related to the underlying problem.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论