Ethan D'Mello
Ethan D'Mello

Reputation: 119

Trying to wipe out pasteboard after time interval

I am trying to clear the pasteboard after a string is copied after 10s. The requirements are the following:

  1. After 10s, the copied text is cleared and therefore not pasteable in the current app and other apps as well(ex. iMessage, Safari)
  2. If non-identical text is copied, when the 10s is up the timer will not wipe it out

Attempts

  1. I have tried doing this with only DispatchQueue.main.async however, this was freezing the original app.
  2. I have tried doing it with only DispatchQueue.global(qos: .background).async however, when I switched to another app(iMessage), after 10s I could still paste the number. I had to go back to the original app and back to iMessage for it to be wiped out
  3. This is my latest attempt and its the same behavior as #2, only getting wiped out when I go back to the original app and back to iMessage
    private func clearTextAfterDelay(_ copiedCardNumber: String) {
        expirationTimer?.invalidate()
        expirationTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { timer in
            DispatchQueue.main.async {
                let currentTextOnClipBoard = UIPasteboard.general.string
                if currentTextOnClipBoard == copiedCardNumber {
                    UIPasteboard.general.setValue("", forPasteboardType: UIPasteboard.Name.general.rawValue)
                }
            }
        }

        DispatchQueue.global(qos: .background).async {
            let runLoop = RunLoop.current
            runLoop.add(self.expirationTimer!, forMode: .default)
            runLoop.run()
        }
    }

Upvotes: 2

Views: 825

Answers (2)

Ethan D'Mello
Ethan D'Mello

Reputation: 119

Along with this article and the above comment I was able to figure it out https://medium.com/@abhimuralidharan/finite-length-tasks-in-background-ios-swift-60f2db4fa01b. Cheers

class ViewController: MvpViewController {

    private var expirationTimerforBackground: Timer?
    private var backgroundTask: UIBackgroundTaskIdentifier = UIBackgroundTaskIdentifier.invalid

    private func clearTextAfterDelay(_ copiedCardNumber: String) {
        backgroundTask = UIApplication.shared.beginBackgroundTask { [weak self] in
            self?.endBackgroundTask()
        }

        assert(backgroundTask != UIBackgroundTaskIdentifier.invalid)

        self.expirationTimerforBackground?.invalidate()
        self.expirationTimerforBackground = Timer.scheduledTimer(withTimeInterval: 10, repeats: false) { [weak self] _ in
            let currentTextOnClipBoard = UIPasteboard.general.string
            if currentTextOnClipBoard == copiedCardNumber {
                UIPasteboard.general.setValue("", forPasteboardType: UIPasteboard.Name.general.rawValue)
            }
            self?.endBackgroundTask()
        }
    }

    private func endBackgroundTask() {
        UIApplication.shared.endBackgroundTask(backgroundTask)
        backgroundTask = UIBackgroundTaskIdentifier.invalid
    }
}

Upvotes: 4

Juri Noga
Juri Noga

Reputation: 4391

Number 2 doesn't work because your app gets suspended almost immediately upon resigning active. So you'd need to extend your app's active time by using background tasks.

Take a look at the beginBackgroundTaskWithExpirationHandler docs.

This method requests additional background execution time for your app. Call this method when leaving a task unfinished might be detrimental to your app’s user experience. For example, call this method before writing data to a file to prevent the system from suspending your app while the operation is in progress.

Upvotes: 3

Related Questions