ios 从闭包调用.send()时SwiftUI PassthroughSubject不工作

e3bfsja2  于 2023-05-19  发布在  iOS
关注(0)|答案(1)|浏览(128)

当我试图从一个使用带有确认按钮的闭包的视图中发送一个带有PassthroughSubject var的事件信号时,我遇到了一些问题。
为了在上下文中,我构建了两个视图:SavedRewardsView和WishListItemCard。WishListItemCard使用PassthroughSubject发出事件,SavedRewardsView使用.onReceive属性接收事件。
到目前为止一切顺利,我已经设法发出和捕获WishListItemCard上的事件,实现了一个计数器并更新WishListItemCard中的UI,并将事件发送到SavedRewardsView以更新它的UI。

  • 在WishListItemCard上发送事件:*
@State var redeemCount = 0

let didChange = PassthroughSubject<WishlistItemCounter, Never>()

VStack {
...
}
.onChange(of: self.redeemCount) { newCount in
            
            self.pointsCost = newCount * (self.rewardData.points ?? 0)
            let wic = WishlistItemCounter(rewardId: self.rewardData.id ?? 0, quantity: newCount, total: self.pointsCost)
            self.didChange.send(wic)
        }
  • 在SavedRewardsView上捕获事件:*
let wishlistItemCard = WishlistItemCard()

wishlistItemCard.onReceive(wishlistItemCard.didChange) { newWishlistItemCounter in
            print("wishlistItemCard.didChange")
}

问题在另一个事件上,该事件也需要从WishListItemCard发送。预期的功能是用户应该能够基于确认消息从愿望列表中删除项目,并且由于这是从SavedRewardsView调用的视图,因此需要重新加载数据,以便删除的项目不再出现在列表中。因此,在删除按钮的操作中,有一个自定义警报的调用,该警报需要一个标题和2个操作:一个用于确认动作,另一个用于取消动作。我在confirm操作中发送事件:

  • 在SavedRewardsView上发送事件:*
let didDeleteReward = PassthroughSubject<Bool, Never>()

Button(action: {

            let confirmDeleteButton = CustomAlertButton(title: "Confirm", action: {
                        self.myAppManager.hideAlert()
                        self.didDeleteReward.send(true)
            }

            let cancelButton = CustomAlertButton(title: "Cancel", action: {
                        self.myAppManager.hideAlert()
            }

            self.myAppManager.showAlert(
                        message: "Delete item?",
                        dismissButton: cancelDeleteButton,
                        primaryButton: confirmDeleteButton
                    )

},
label: {
            Image("TrashIcon")
                        .resizable()
                        .scaledToFit()
                        .frame(width: 25, height: 25)
})

并尝试在SavedRewardsView上接收事件,但此处未捕获该事件:

let wishlistItemCard = WishlistItemCard()

wishlistItemCard
.onReceive(wishlistItemCard.didChange) { newWishlistItemCounter in
            print("wishlistItemCard.didDeleteReward")
            Task {
                await self.reloadData()
            }
}

以下是我尝试过的:
1.使用@State变量并将其附加到.onReceive并发送事件,但SavedRewardsView上未捕获该事件。
1.使用CurrentValueSubject,但值本身会一直更新,成为一个无限的更新循环。
1.将 self.didDeleteReward.send(true) 直接放置在按钮的操作上,没有确认消息,事件将在SavedRewardsView上捕获,但它不是预期的行为,因为它需要确认。
你们能帮帮我吗,我真的没办法了。

  • 注意:myAppManager var是一个ObservableObject,它是我的应用程序的真实来源,并且从第一个扩展App的视图中分层传递到具有.environmentObject的视图。
juud5qan

juud5qan1#

SwiftUI已经内置了passthrough subjects(尽管它被称为依赖跟踪或更改检测),所以你不需要自己重新创建它,只需执行以下操作:

struct SavedRewardsView: View {
    @State var redeemCount = 0

    // When redeemCount's getter is called in body, SwiftUI sets up subjects to monitor the value and when the setter is called, SwiftUI will call body again to get all the new child Views.
    var body: some View {
       ...

       SavedRewardsView(redeemCount: redeemCount)
       ...
    }
}

// Although this will be init many times, body will only be called when required.
struct SavedRewardsView: View {

    // SwiftUI will monitor the value of this let
    let redeemCount: Int

    var body: some View {
        // SwiftUI will monitor the value of redeemCount and body will be called when it changes
    }
}

body看作是View中声明的所有let@State vardidChange函数。

相关问题