在函数中使用 “any generic” 导致 “_ErrorCodeProtocol has no member” 错误。

huangapple go评论91阅读模式
英文:

Swift: "any generic" in function causes "_ErrorCodeProtocol has no member" error

问题

Swift 5.8 使用 'any generic' 导致奇怪的错误 (_ErrorCodeProtocol)

你好!在我的宠物项目中,我想要减少 UIKit 的布局代码(我使用程序化的 UI 布局)。我的想法是为我的宠物项目创建一个用于最常见情况的枚举,例如:

  1. // view 是一个视图控制器的视图
  2. let searchArea = UIView()
  3. view.addSubview(searchArea)
  4. searchArea.applyConstraints(
  5. .alignTopWithTop(of: guide),
  6. .alignLeadingWithLeading(of: view),
  7. .alignTrailingWithTrailing(of: view),
  8. .alignHeight(with: view, mult: 0.1)
  9. )

我真的很喜欢它,比起下面的方式更好:

  1. let searchArea = UIView()
  2. view.addSubview(searchArea)
  3. object.translatesAutoresizingMaskIntoConstraints = false
  4. NSLayoutConstraint.activate([
  5. searchArea.topAnchor.constraint(equalTo: view.topAnchor, constant: 0),
  6. searchArea.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
  7. searchArea.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
  8. searchArea.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1, constant: 0)
  9. ])

因为 UIViews 应该与其他 UIView 子视图以及 UIViewController 安全区域 (UILayoutGuide) 对齐,我使用了泛型来实现这一点:

  1. protocol UISnapable {
  2. var leadingAnchor: NSLayoutXAxisAnchor { get }
  3. // 这里包括 UIView 和 UILayoutGuide 同时拥有的其他锚点
  4. var centerYAnchor: NSLayoutYAxisAnchor { get }
  5. }
  6. extension UIView: UISnapable {}
  7. extension UILayoutGuide: UISnapable {}
  8. enum Constraints<T: UISnapable> {
  9. case alignTopWithTop(of: T, const: CGFloat = 0)
  10. // 还有其他对齐情况
  11. case setAspectWidth(ratio: CGFloat)
  12. }
  13. func applyConstraints(object: inout UIView, constraints: any UISnapable...) {
  14. object.translatesAutoresizingMaskIntoConstraints = false
  15. NSLayoutConstraint.activate(
  16. // 将输入的可变参数转换为约束
  17. constraints.map {
  18. switch $0 {
  19. case .alignTopWithTop(of: let of, const: let const):
  20. return object.topAnchor.constraint(
  21. equalTo: of.topAnchor,
  22. constant: const
  23. )
  24. // 其他对齐情况
  25. case .setAspectWidth(ratio: let ratio):
  26. return object.heightAnchor.constraint(
  27. equalTo: object.widthAnchor,
  28. multiplier: ratio
  29. )
  30. }
  31. }
  32. )
  33. }

我在泛型 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:

  1. // view is a view controller&#39;s view
  2. let searchArea = UIView()
  3. view.addSubview(searchArea)
  4. searchArea.applyConstraints(
  5. .alignTopWithTop(of: guide),
  6. .alignLeadingWithLeading(of: view),
  7. .alignTrailingWithTrailing(of: view),
  8. .alignHeight(with: view, mult: 0.1)
  9. )

I really like it much more than:

  1. let searchArea = UIView()
  2. view.addSubview(searchArea)
  3. object.translatesAutoresizingMaskIntoConstraints = false
  4. NSLayoutConstraint.activate([
  5. searchArea.topAnchor.constraint(equalTo: view.topAnchor, constant: 0),
  6. searchArea.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0),
  7. searchArea.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0),
  8. searchArea.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.1, constant: 0)
  9. ])

Because UIViews should be aligned to other UIView childs as well as UIViewController safe Area (UILayoutGuide) I implemented this using generics:

  1. protocol UISnapable {
  2. var leadingAnchor: NSLayoutXAxisAnchor { get }
  3. // Here are other anchors that UIView and UILayoutGuide have at the same time
  4. var centerYAnchor: NSLayoutYAxisAnchor { get }
  5. }
  6. extension UIView: UISnapable {}
  7. extension UILayoutGuide: UISnapable {}
  8. enum Constraints&lt;T: UISnapable&gt; {
  9. case alignTopWithTop(of: T, const: CGFloat = 0)
  10. // Other align cases here
  11. case setAspectWidth(ratio: CGFloat)
  12. }
  13. func applyConstraints(object: inout UIView, constraints: any UISnapable...) {
  14. object.translatesAutoresizingMaskIntoConstraints = false
  15. NSLayoutConstraint.activate(
  16. // Transforming input variadic to constraints
  17. constraints.map {
  18. switch $0 {
  19. case .alignTopWithTop(of: let of, const: let const):
  20. return object.topAnchor.constraint(
  21. equalTo: of.topAnchor,
  22. constant: const
  23. )
  24. // Other align cases here
  25. case .setAspectWidth(ratio: let ratio):
  26. return object.heightAnchor.constraint(
  27. equalTo: object.widthAnchor,
  28. multiplier: ratio
  29. )
  30. }
  31. }
  32. )
  33. }

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&amp;type=Documentation)

答案1

得分: 1

你传递的是UISnapable列表,但你的意思是传递Constraints列表。在这种情况下,你将any放在了错误的位置。

我认为你的意思是这样的:

  1. // Constraints不是泛型,但在某些情况下可以容纳任何UISnapable
  2. enum Constraints {
  3. // 使用`any UISnapable`而不是T
  4. case alignTopWithTop(of: any UISnapable, const: CGFloat = 0)
  5. // 在这里添加其他对齐情况
  6. case setAspectWidth(ratio: CGFloat)
  7. }

然后方法是(请注意,这里的inout是不必要的;UIView是一个引用类型):

  1. func applyConstraints(object: inout UIView, constraints: Constraints...) {
  2. ^^^^^^^^^^^

至于错误,编译器之所以困惑,是因为你正尝试switch一个非枚举类型(这里的$0any 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:

  1. // Constraints are not generic, but they can hold any UISnapable in some cases
  2. enum Constraints {
  3. // Use `any UISnapable` rather than T
  4. case alignTopWithTop(of: any UISnapable, const: CGFloat = 0)
  5. // Other align cases here
  6. case setAspectWidth(ratio: CGFloat)
  7. }

And then the method is (note that the inout here is unnecessary; UIView is a reference type):

  1. func applyConstraints(object: inout UIView, constraints: Constraints...) {
  2. ^^^^^^^^^^^

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.

huangapple
  • 本文由 发表于 2023年5月30日 02:13:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/76359530.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定