HomeiOS Developmentios - How one can outline onTapGesture with debounce in SwiftUI utilizing...

ios – How one can outline onTapGesture with debounce in SwiftUI utilizing PassThroughSubject easier approach than modifier, ViewModifier and Mannequin inside?


A debounce operation may be applied by ready inside a process(id:). Change the id parameter in onTapGesture to begin a brand new process. If one other faucet happens in the course of the Job.sleep name, the duty will probably be cancelled and so Job.sleep will throw an error.

struct DebounceTapModifier: ViewModifier {
    non-public let motion: () -> Void
    non-public let debounce: CGFloat
    
    @State non-public var taskTrigger: Bool?
    
    init(motion: @escaping () -> Void, debounce: CGFloat) {
        self.motion = motion
        self.debounce = debounce
    }
    
    func physique(content material: Content material) -> some View {
        content material
            .onTapGesture {
                taskTrigger = !(taskTrigger ?? false)
            }
            .process(id: taskTrigger) {
                guard taskTrigger != nil { return } // the consumer has not tapped but
                do {
                    strive await Job.sleep(for: .seconds(debounce))
                    // if Job.sleep throws an error, motion is not going to be known as
                    motion()
                } catch {
                    // one other faucet occurred in the course of the debounce period
                }
            }
    }
}

As in your Mix method, the lifetime of DebounceViewModel is just not being managed by SwiftUI. I’d make it an ObservableObject and put it in a @StateObject, in order that its lifetime is similar because the view modifier.

class Debouncer: ObservableObject {
    var cancellable: (any Cancellable)?
    let topic = PassthroughSubject()
    
    deinit {
        print("deinit")
    }
}

struct DebounceTapModifier: ViewModifier {
    non-public let motion: () -> Void
    non-public let debounce: CGFloat
    non-public var debouncer = Debouncer()
    
    init(motion: @escaping () -> Void, debounce: CGFloat) {
        self.motion = motion
        self.debounce = debounce
    }
    
    func physique(content material: Content material) -> some View {
        content material
            .onTapGesture {
                debouncer.topic.ship(0)
            }
            .onChange(of: debounce) {
                // redo the writer subscription if the debounce time has modified
                // if debounce is at all times the identical then you possibly can simply do that in onAppear
                setupActions()

                 // *don't* name setupActions within the initialiser. The StateObject has not but been "put in" at the moment.
            }
    }
    
    non-public func setupActions() {
        debouncer.cancellable = debouncer.topic
            .debounce(for: .seconds(debounce), scheduler: DispatchQueue.principal)
            .sink { _ in
                motion()
            }
    }
}

RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

- Advertisment -
Google search engine

Most Popular

Recent Comments