Skip to content

Instantly share code, notes, and snippets.

@zats
Last active July 2, 2019 10:45
Show Gist options
  • Save zats/de9482e441abd5eb33ac to your computer and use it in GitHub Desktop.
Save zats/de9482e441abd5eb33ac to your computer and use it in GitHub Desktop.
UIPreviewActionItem for SFSafariViewController through delegation not subclassing

Adding UIPreviewActionItem to SFSafariViewController might be a tedious task. This extansion should help.

let vc = SFSafariViewController(initialURL: url, entersReaderIfAvailable: true)
vc.previewActionItemsDelegate = self

When presenting SFSafariViewController use convenience initializer that will store original URL for later, it'll make custom action requiring original URL easier. But it's not mandatory.

Here is the delegate implementation, this is where we might want to use initialURL

func safariViewControllerPreviewActionItems(controller: SFSafariViewController) -> [UIPreviewActionItem] {
    var actions: [UIPreviewActionItem] = []
    if let url = controller.initialURL {
        // Only if we know initialURL
        let action1 = UIPreviewAction(title: "Action 1", style: .Default, handler: { action, controller in
            print("action1 for initial URL \(url)")
        })
        actions.append(action1)
    }
    let action2 = UIPreviewAction(title: "Action 2", style: .Default, handler: { action, controller in
        print("action1")
    })
    actions.append(action2)
    return actions
}
import SafariServices
import ObjectiveC
private struct AssociatedKeys {
static var PreviewActionItemsDelegateName = "previewActionItemsDelegate"
static var InitialURL = "initialURL"
}
extension SFSafariViewController {
private(set) public var initialURL: NSURL? {
set {
objc_setAssociatedObject(self, &AssociatedKeys.InitialURL, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
get {
return objc_getAssociatedObject(self, &AssociatedKeys.InitialURL) as? NSURL
}
}
public convenience init(initialURL: NSURL, entersReaderIfAvailable: Bool) {
self.init(URL: initialURL, entersReaderIfAvailable: entersReaderIfAvailable)
self.initialURL = initialURL
}
}
// Preview action items
extension SFSafariViewController {
weak var previewActionItemsDelegate: SFSafariViewControllerPreviewActionItemsDelegate? {
set {
objc_setAssociatedObject(self, &AssociatedKeys.PreviewActionItemsDelegateName, newValue, .OBJC_ASSOCIATION_ASSIGN)
}
get {
return objc_getAssociatedObject(self, &AssociatedKeys.PreviewActionItemsDelegateName) as? SFSafariViewControllerPreviewActionItemsDelegate
}
}
public override func previewActionItems() -> [UIPreviewActionItem] {
return previewActionItemsDelegate?.safariViewControllerPreviewActionItems(self) ?? []
}
}
public protocol SFSafariViewControllerPreviewActionItemsDelegate: class {
func safariViewControllerPreviewActionItems(controller: SFSafariViewController) -> [UIPreviewActionItem]
}
@inPhilly
Copy link

Do you have a way to do this through objective c? It looks great.

@zats
Copy link
Author

zats commented Jun 4, 2016

All the API I used is objective c API. You can literally rewrite it in objective c as is and it should work

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment