В моем приложении я хочу сделать session timeout через некоторое время inactivity. Но если пользователь взаимодействует с приложением, необходимо сбросить timer.

Основная проблема заключается в том, что это должно быть реализовано в части приложения, а не для всего приложения, поэтому есть ли альтернатива подклассу UIApplication для обнаружения user interaction.

У меня есть базовый класс для этого конкретного контроллера, но touch or gesture delegates не вызывается в базовом классе.

Как я могу обнаружить взаимодействие с пользователем для нескольких контроллеров.

Заранее благодарим за любые идеи и помощь.

0
Shruti 13 Сен 2021 в 09:13

2 ответа

Лучший ответ

Итак, я придумал способ. В моем базовом классе я раньше устанавливал жест касания для просмотра.

    let tap =  UITapGestureRecognizer(target: self, action: nil)
    tap.delegate = self
    tap.cancelsTouchesInView = false
    view.addGestureRecognizer(tap)

Поэтому вместо view.addGestureRecognizer(tap) теперь я добавляю жест на window

    if let window = UIApplication.shared.keyWindow {
        window.addGestureRecognizer(tap)
    }

И я реализовал UIGestureRecognizerDelegate

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { 
 // My Code here
   return true
}

Итак, теперь мой базовый класс может обнаруживать любые нажатия и вызывать delegate.

Обратите внимание: добавление этого delegate/ gesture не влияет на прикосновение или жест в любом другом представлении моих дочерних классов.

0
Shruti 13 Сен 2021 в 12:11

Я не думаю, что есть другой способ сделать это, кроме подкласса UIApplication / UIWindow. Если вам нужны инструкции по созданию подкласса UIApplication для отслеживания событий, следуйте этому ответу

Вы можете добавить возможность наблюдать за бездействием в своем приложении. Когда есть подписчики, таймер работает, иначе - нет.

final class CustomUIApplication: UIApplication {
    override class var shared: CustomUIApplication {
        super.shared as! CustomUIApplication
    }

    let inactivityInterval: TimeInterval = 10 * 60 // 10 minutes

    private var inactivityHandlers = [ClosureWrapper]()
    private var timer: Timer? {
        didSet {
            oldValue?.invalidate()
        }
    }

    override func sendEvent(_ event: UIEvent) {
        super.sendEvent(event)
        if !inactivityHandlers.isEmpty {
            restartTimer()
        }
    }

    func observeInactivity(_ handler: @escaping () -> Void) -> InactivityObservation {
        let closureWrapper = ClosureWrapper(closure: handler)
        inactivityHandlers.append(closureWrapper)
        if timer == nil {
            restartTimer()
        }
        return InactivityObservation { [self] in
            if let index = inactivityHandlers.firstIndex(of: closureWrapper) {
                inactivityHandlers.remove(at: index)
                if inactivityHandlers.isEmpty {
                    timer = nil
                }
            }
        }
    }

    private func restartTimer() {
        timer = Timer.scheduledTimer(withTimeInterval: inactivityInterval, repeats: false) { [self] _ in
            inactivityHandlers.forEach { $0.closure() }
            timer = nil
        }
    }
}

final class InactivityObservation {
    let invalidator: () -> Void

    init(invalidator: @escaping  () -> Void) {
        self.invalidator = invalidator
    }

    deinit {
        invalidator()
    }
}

private final class ClosureWrapper: Equatable {
    static func ==(lhs: ClosureWrapper, rhs: ClosureWrapper) -> Bool {
        lhs === rhs
    }

    let closure: () -> Void

    init(closure: @escaping  () -> Void) {
        self.closure = closure
    }
}

Затем вы можете подписаться на отслеживание в любом контроллере представления.

class ViewController: UIViewController {
    var inactivityObservation: InactivityObservation?

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        inactivityObservation = CustomUIApplication.shared.observeInactivity {
            print("inactive")
        }
    }

    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        inactivityObservation = nil
    }
}
0
Philip Dukhov 13 Сен 2021 в 11:12