简体   繁体   English

SwiftUI 的 onAppear() 和 onDisappear() 在 Xcode 12.1 上多次调用且不一致

[英]SwiftUI's onAppear() and onDisappear() called multiple times and inconsistently on Xcode 12.1

I've come across some strange behavior with SwiftUI's onAppear() and onDisappear() events.我在 SwiftUI 的onAppear()onDisappear()事件中遇到了一些奇怪的行为。 I need to be able to reliably track when a view is visible to the user, disappears, and any other subsequent appear/disappear events (the use case is tracking impressions for mobile analytics).我需要能够可靠地跟踪视图何时对用户可见、消失以及任何其他后续出现/消失事件(用例是跟踪移动分析的印象)。

I was hoping to leverage the onAppear() and onDisappear() events associated with swiftUI views, but I'm not seeing consistent behavior when using those events.我希望利用与 swiftUI 视图关联的onAppear()onDisappear()事件,但在使用这些事件时我没有看到一致的行为。 The behavior can change depending on view modifiers as well as the simulator on which I run the app.行为可能会根据视图修改器以及我运行应用程序的模拟器而改变。

In the example code listed below, I would expect that when ItemListView2 appears, I would see the following printed out in the console:在下面列出的示例代码中,我希望当ItemListView2出现时,我会在控制台中看到以下内容:

button init
button appear

And on the iPhone 8 simulator, I see exactly that.在 iPhone 8 模拟器上,我完全看到了这一点。

However, on an iPhone 12 simulator, I see:但是,在 iPhone 12 模拟器上,我看到:

button init
button appear
button disappear
button appear

Things get even weirder when I enable the listStyle view modifier:当我启用listStyle视图修饰符时,事情变得更加奇怪:

button init
button appear
button disappear
button appear
button disappear
button appear
button appear

The iPhone 8, however remains consistent and produces the expected result.然而,iPhone 8 保持一致并产生了预期的结果。

I should also note that in no case, did the Button ever seem to disappear and re-appear to the eye.我还应该指出,在任何情况下,按钮似乎都不会消失并重新出现在眼前。

These inconsistencies are also not simulator only issues, i noticed them on devices as well.这些不一致也不只是模拟器的问题,我在设备上也注意到了它们。

I need to reliably track these appear/disappear events.我需要可靠地跟踪这些出现/消失的事件。 For example I'd need to know when a cell in a list appears (scrolled into view) or disappears (scrolled out of view) or when, say a user switches tabs.例如,我需要知道列表中的单元格何时出现(滚动到视图中)或消失(滚动出视图)或何时,比如说用户切换选项卡。

Has anyone else noticed this behavior?有没有其他人注意到这种行为? To me this seems like a bug in SwiftUI, but I'm not certain as I've not used SwiftUI enough to trust myself to discern a programmer error from an SDK error.对我来说,这似乎是 SwiftUI 中的一个错误,但我不确定,因为我没有充分使用 SwiftUI 来相信自己能够从 SDK 错误中辨别出程序员错误。 If any of you have noticed this, did you find a good work-around / fix?如果你们中有人注意到这一点,您是否找到了一个好的解决方法/修复方法?

Thanks,谢谢,

  • Norm规范
// Sample code referenced in explanation
// Using Xcode Version 12.1 (12A7403) and iOS 14.1 for all simulators
import SwiftUI

struct ItemListView2: View {

    let items = ["Cell 1", "Cell 2", "Cell 3", "Cell 4"]

    var body: some View {
        ListingView(items: items)
    }
}

private struct ListingView: View {
    let items: [String]

    var body: some View {
        List {
            Section(
                footer:
                    FooterButton()
                    .onAppear { print("button appear") }
                    .onDisappear { print("button disappear") }
            ) {
                ForEach(items) { Text($0) }
            }
        }
//      .listStyle(GroupedListStyle())
    }
}

private struct FooterButton: View {
    init() {
        print("button init")
    }
    var body: some View {
        Button(action: {}) { Text("Button")  }
    }
}

In SwiftUI you don't control when items in a List appear or disappear .在 SwiftUI 中,您无法控制List中的项目何时出现消失 The view graph is managed internally by SwiftUI and views may appear/disappear at any time.视图图由 SwiftUI 内部管理,视图可能随时出现/消失。

You can, however, attach the onAppear / onDisappear modifiers to the outermost view:但是,您可以将onAppear / onDisappear修饰符附加到最外面的视图:

List {
    Section(footer: FooterButton()) {
        ForEach(items, id: \.self) { 
            Text($0) 
        }
    }
}
.listStyle(GroupedListStyle())
.onAppear { print("list appear") }
.onDisappear { print("list disappear") }

Try this UIKit approach.试试这个 UIKit 方法。 Similar behavior continues to exist under iOS 14.类似行为在 iOS 14 下继续存在。

protocol RemoteActionRepresentable: AnyObject {
    func remoteAction()
}

struct UIKitAppear: UIViewControllerRepresentable {
    let action: () -> Void
    
    func makeUIViewController(context: Context) -> UIAppearViewController {
       let vc = UIAppearViewController()
        vc.delegate = context.coordinator
        return vc
    }
    
    func updateUIViewController(_ controller: UIAppearViewController, context: Context) {}
    
    func makeCoordinator() -> Coordinator {
        Coordinator(action: self.action)
    }
    
    class Coordinator: RemoteActionRepresentable {
        
        var action: () -> Void
        
        init(action: @escaping () -> Void) {
            self.action = action
        }
        
        func remoteAction() {
            action()
        }
    }
}

class UIAppearViewController: UIViewController {
    weak var delegate: RemoteActionRepresentable?
    
    override func viewDidLoad() {
        view.addSubview(UILabel())
    }
    override func viewDidAppear(_ animated: Bool) {
        delegate?.remoteAction()
    }
}

extension View {
    func onUIKitAppear(_ perform: @escaping () -> Void) -> some View {
        self.background(UIKitAppear(action: perform))
    }
}

Example:例子:

var body: some View {
    MyView().onUIKitAppear {
        print("UIViewController did appear")
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM