swift - @ObjectBinding 不适用于协议(protocol)

标签 swift swiftui

我有一个 SwiftUI View ,它有一个 @ObjectBinding progression: Progressable 像这样:

struct ProgressBarComponent : View {
  @ObjectBinding var progression: Progressable
  var progressAnimation: Animation {
    Animation
    .spring(stiffness: 43, initialVelocity: 3.2)
    .speed(3)
    .delay(0.07)
  }

  var body: some View {
    VStack {
      HStack {
        Text(self.progression.name)
          .font(.subheadline)
          .color(.gray)
        Spacer()
        Text(self.progression.description)
          .font(.subheadline)
          .color(.gray)
      }
        .padding(.bottom, -8)
        .padding(.horizontal, 4)
      ZStack {
        GeometryReader { geometry in
          Capsule()
          .fill(
            Color(.displayP3,
              red: 150 / 255,
              green: 150 / 255,
              blue: 150 / 255,
              opacity: 0.1)
          )
          .overlay(
            ZStack(alignment: .leading) {
              Circle()
                .fill(self.progression.gradient)
                .position(x: 7, y: 7)
              Capsule()
                .size(
                  width: geometry.size.width * self.progression.progress,
                  height: geometry.size.height)
                .fill(self.progression.gradient)
                .animation(self.progressAnimation)
            }
          )
        }
      }
        .frame(width: nil, height: 14, alignment: .leading)
    }
      .padding()
  }
}

我创建的协议(protocol)如下所示:

protocol Progressable: BindableObject {
  var name: String { get }
  var description: String { get }
  var progress: CGFloat { get }
  var gradient: LinearGradient { get set }
}

最后,我有一个实现 Progressable 协议(protocol)的类 BaseNutrient:

class BaseNutrient: Progressable {
  let unitFormatter = NumberFormatter()

  var didChange = PassthroughSubject<BaseNutrient, Never>()

  var name: String
  var description: String {
    get {
      return
        "\(unitFormatter.string(from: NSNumber(value: Float(current)))!) / \(unitFormatter.string(from: NSNumber(value: Float(total)))!) \(unit.rawValue)"
    }
  }

  var unit: NutrientUnit

  var current: CGFloat
  var total: CGFloat
  var progress: CGFloat {
    get {
      return current / total
    }
  }

  var gradient: LinearGradient

  init(name: String, unit: NutrientUnit, total: CGFloat, colors: [Color] = [Color(red: 239.0 / 255, green: 120.0 / 255, blue: 221.0 / 255), Color(red: 239.0 / 255, green: 172.0 / 255, blue: 120.0 / 255)], start: CGFloat = 0) {
    self.name    = name
    self.unit    = unit
    self.total   = total
    self.current = start

    unitFormatter.locale = Locale.current
    unitFormatter.numberStyle = .decimal
    unitFormatter.maximumFractionDigits = 0

    gradient = LinearGradient(gradient: .init(colors: colors), startPoint: .init(x: 0.0, y: 0),
        endPoint: .init(x: 1.0, y: 0))
  }

  func addProgress(_ progress: CGFloat) {
    current += progress
    if current > total {
      current = total
    }
    didChange.send(self)
  }

  func removeProgress(_ progress: CGFloat) {
    current -= progress
    if current < 0 {
      current = 0
    }
    didChange.send(self)
  }

}

如果我在 SwiftUI View 中使用 BaseNutrient 作为类型来代替 Progressable,一切都可以正常编译和运行。如果我改用 Progressable 协议(protocol),构建永远不会完成,只会挂起,永远不会给我任何错误。有谁知道会发生什么?

最佳答案

当您使用 Progressable 时作为直接类型,编译无法推断出 BindableObject.PublisherType关联类型。

添加<P: Progressable>将帮助编译器。 不幸的是,编译器只是挂起并且没有给出合理的错误消息。

参见:

struct ProgressBarComponent<P: Progressable> : View {
    @ObjectBinding var progression: P

…

关于swift - @ObjectBinding 不适用于协议(protocol),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56709268/

相关文章:

ios - if 条件在 swift ios 的 json 响应中

ios - UILabel 具有背景 View + 遵循文本布局的填充

image - 如何将图像转换为 UIImage?

swift - macOS SwiftUI : how to trigger deleting an item?

ios - 如何通过 UITapGestureRecognizer 将数据从一个 UIViewController 传递到另一个 UIViewController

ios - 更改 Safari View Controller 完成按钮色调?

swift - 区分 NSFileWrapper 和目录?

ios - 当ViewModel获取新数据时, View 未更新

ios - NavigationView 下的 SwiftUI WKWebView 不接受 displayMode

swiftui - 如何在 SwiftUI 中创建可点击的网址/电话号码