Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding a second UIWindow to display the UIAlertController. #18

Merged
merged 2 commits into from
May 5, 2015
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions Sample App/Sample App/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Required
siren.appID = "376771144" // For this example, we're using the iTunes Connect App (https://itunes.apple.com/us/app/itunes-connect/id376771144?mt=8)

// Required
siren.presentingViewController = window?.rootViewController

// Optional
siren.delegate = self

Expand Down
49 changes: 37 additions & 12 deletions Siren/Siren.swift
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,6 @@ public class Siren: NSObject
*/
public var appID: String?

/**
The view controller that will present the instance of UIAlertController.

It is recommended that you set this value to window?.rootViewController.

This property must be set before calling checkVersion().
*/
public var presentingViewController: UIViewController?

// Optional Vars
/**
The name of your app.
Expand Down Expand Up @@ -235,8 +226,6 @@ public class Siren: NSObject

if (appID == nil) {
println("[Siren] Please make sure that you have set 'appID' before calling checkVersion.")
} else if (useAlertController && presentingViewController == nil) { // iOS 8 only
println("[Siren] Please make sure that you have set 'presentingViewController' before calling checkVersion.")
} else {
if checkType == .Immediately {
performVersionCheck()
Expand Down Expand Up @@ -377,7 +366,19 @@ private extension Siren
}

if alertType != .None {
presentingViewController?.presentViewController(alertController, animated: true, completion: nil)
/*
Show the UIAlertController from the rootViewController of a second UIWindow.
That way we don't have to worry about which UIViewController is currently being presented.
*/
if UIApplication.sharedApplication().updaterWindow == nil {
let window = UIWindow(frame: UIScreen.mainScreen().bounds)
window.rootViewController = UIViewController()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see that this fixes the rotation issue I thought would exist. Clever! Have you tested this code on iOS 7? Does it still work as expected?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm fairly certain that it will work on iOS 7, but I'll test and confirm.

window.windowLevel = UIWindowLevelAlert + 1 // make the window appear above all other view controllers and windows
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This relies on undocumented behavior - I suggest we stick with UIWindowLevelAlert.

UIApplication.sharedApplication().updaterWindow = window
}

UIApplication.sharedApplication().updaterWindow.makeKeyAndVisible()
UIApplication.sharedApplication().updaterWindow.rootViewController!.presentViewController(alertController, animated: true, completion: nil)
}

} else { // iOS 7
Expand Down Expand Up @@ -409,6 +410,7 @@ private extension Siren
func updateAlertAction() -> UIAlertAction {
let title = localizedUpdateButtonTitle()
let action = UIAlertAction(title: title, style: .Default) { (alert: UIAlertAction!) -> Void in
self.hideAlertWindow()
self.launchAppStore()
self.delegate?.sirenUserDidLaunchAppStore?()
return
Expand All @@ -420,6 +422,7 @@ private extension Siren
func nextTimeAlertAction() -> UIAlertAction {
let title = localizedNextTimeButtonTitle()
let action = UIAlertAction(title: title, style: .Default) { (alert: UIAlertAction!) -> Void in
self.hideAlertWindow()
self.delegate?.sirenUserDidCancel?()
return
}
Expand All @@ -430,12 +433,34 @@ private extension Siren
func skipAlertAction() -> UIAlertAction {
let title = localizedSkipButtonTitle()
let action = UIAlertAction(title: title, style: .Default) { (alert: UIAlertAction!) -> Void in
self.hideAlertWindow()
self.delegate?.sirenUserDidSkipVersion?()
return
}

return action
}

func hideAlertWindow() {
UIApplication.sharedApplication().updaterWindow.hidden = true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this remove the window entirely? It's rare that it'll get used again. It might be nice to free up the memory, however minor.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good feedback. We can remove it from memory by calling updaterWindow = nil after hiding it.

}
}

//MARK: Updater Window
private var UpdaterWindowAssociationKey: UInt8 = 8

private extension UIApplication {

// UIWindows need to be strongly referenced otherwise they will be released before they are displayed
var updaterWindow: UIWindow! {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is clever, but why store the UIWindow on the application object at all? We can store it more simply within Siren.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're absolutely right. This is an artifact from my implementation. I used class functions instead of an instance.

I'll remove it and add a property to the instance.

get {
return objc_getAssociatedObject(self, &UpdaterWindowAssociationKey) as? UIWindow
}
set {
objc_setAssociatedObject(self, &UpdaterWindowAssociationKey, newValue, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN_NONATOMIC))
}
}

}

// MARK: Helpers
Expand Down