Global state in SafariExtensionHandler

Hello,


Is there a way to manage a global state in the SafariExtensionHandler


I try to enable the toolbar button of my Safari extension only if certain conditions fit on the current webpage.


Therefor I try to use the

override func validateToolbarItem(in window: SFSafariWindow, validationHandler: ((Bool, String) -> Void))

function which is documented for this usage.


In this function I send a message to the active page like this and store the validationHandler in a property of the SafariExtensionHandler

window.getActiveTab(completionHandler: {
                $0?.getActivePage(completionHandler: {
                    page in
                    page?.dispatchMessageToScript(withName: "shouldBeOn", userInfo: nil)
                })
            })


And then I handle this message in my injected script which checks for my condition there.

The scripts then sends back message wether it fullfills the condition or not.


Depending on this I try to call the validationHandler with true or false.


My problem is that the stored validationHandler vanishes (or the message pass call from the script creates a new instance of the SafariExtensionHandler). Seems like there is new way to do the validation depending on something related to the injected script which makes no sense for me?


Am I missing something or is this a bug?

Accepted Reply

There is no guarantee that Safari will use the same instance of SafariExtensionHandler each time it calls into your extension.


If you would like to store global state, you should be using a singleton helper class that stays alive for the lifetime of your extension.

Replies

There is no guarantee that Safari will use the same instance of SafariExtensionHandler each time it calls into your extension.


If you would like to store global state, you should be using a singleton helper class that stays alive for the lifetime of your extension.

Thanks didn't think about this! This works

Where could this singleton helper class be instantiated?

To answer my own question, it could be instantiated in SafariExtensionHandler.swift but outside the SafariExtensionHandler class.

Another option is to create it as a static property of a `SafariExtensionHandler` class:

class SafariExtensionHandler: SFSafariExtensionHandler {
  static let stateObject: StateObject = StateObject()
  ...
}

In that case it won't pollute a global state.
Please note that static properties are initialized lazily.