With the aim to implement a splash screen that only shows once i've modified didFinishLaunchingWithOptions
in order to dynamically select the appropriate view controller. The logic seems to work fine, and the view I intended to load is the one launched
However, the UI seems to be missing elements that would otherwise be displayed should I have not altered the didFinishLaunchingWithOptions
function.
func application(application: UIApplication!, didFinishLaunchingWithOptions launchOptions: NSDictionary!) -> Bool
{
window = UIWindow(frame: UIScreen.mainScreen().bounds)
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
var entryViewController: UIViewController?
if NSUserDefaults.standardUserDefaults().boolForKey("hasSeenWelcomeScreen") == true
{
entryViewController = storyBoard.instantiateViewControllerWithIdentifier("NavigationController") as? UIViewController
}
else
{
entryViewController = storyBoard.instantiateViewControllerWithIdentifier("WelcomeViewController") as? UIViewController
NSUserDefaults.standardUserDefaults().setValue(true, forKey: "hasSeenWelcomeScreen")
NSUserDefaults.standardUserDefaults().synchronize()
}
self.window?.rootViewController = entryViewController
self.window?.makeKeyAndVisible()
return true
}
My WelcomeViewController
is a simple view with 1 label
, 1 button
and a movie
which plays in the background (resembling Spotify/Vine's welcome screen). Debugging the code I can see the initialization methods do get executed, but is just the frame that does not seem to be displayed when I dynamically override the initial view
import UIKit
import MediaPlayer
import QuartzCore
class WelcomeViewController: UIViewController {
var moviePlayerController: MPMoviePlayerController = MPMoviePlayerController()
@IBOutlet weak var loginButton: UIButton!
@IBOutlet weak var appNameLabel: UILabel!
override func viewDidLoad()
{
super.viewDidLoad()
buildMoviePreview()
buildButtonDesign()
}
override func viewWillAppear(animated: Bool)
{
self.view.addSubview(self.moviePlayerController.view)
self.view.addSubview(self.loginButton)
self.view.addSubview(self.appNameLabel)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
override func prefersStatusBarHidden() -> Bool {
return true
}
private func buildButtonDesign()
{
loginButton.layer.borderColor = UIColor.whiteColor().CGColor
loginButton.layer.borderWidth = 2.0
loginButton.layer.cornerRadius = 7.0
}
private func buildMoviePreview()
{
let filePath = NSBundle.mainBundle().pathForResource("intro", ofType: "mov")
self.moviePlayerController.contentURL = NSURL.fileURLWithPath(filePath)
self.moviePlayerController.movieSourceType = .File
self.moviePlayerController.repeatMode = .One
self.moviePlayerController.view.frame = self.view.bounds
self.moviePlayerController.scalingMode = .AspectFill
self.moviePlayerController.controlStyle = .None
self.moviePlayerController.allowsAirPlay = false
self.moviePlayerController.shouldAutoplay = true
self.moviePlayerController.play()
}
}
For completeness, these are the discrepancies in the layout when using the XCode UI debugger. Please note that they differ even though they implement the same viewController. The only difference is that one has been programmatically set as the initial view, while the other has been set as the initial view through storyboard.
Screenshots of the rendering issue side-by-side
Your approach is... unusual. A Storyboard has a root view controller for a reason and typically at startup you would just let the application handle loading the storyboard and installing that root view controller as the window's main view controller. (The Storyboard loaded is specified in the application target's general settings as the "Main Interface")
In this case, what I would recommend is making your root view controller the "Normal" view of the application... the one you want users to see when they launch the app on a day-to-day basis.
Define your "on first launch" view controller as a separate view controller in the storyboard and add a modal segue from the root view controller to the on first launch view controller.
Then in your applicationDidFinishLaunching, if the user has never seen the first launch controller... simply ask the Storyboard to take that segue. If the user has already seen the first launch presentation that segue will be skipped.
Another issue I see with your code is in your viewWillAppear method. You should not have to add your views as subviews in viewWillAppear... those subviews should already have been set up at the time the view was loaded from the nib file.
The one exception is the view of your movie player, but your movie player is owned by a separate view controller. That separate view controller is detached from the view controller hierarchy and does not have it's own view controller methods called at the right times. (so it never receives calls like "viewWillAppear" that might tell it to get it's movie ready to play).
What you probably want to do is implement "awakeFromNib" and make sure that the movie player's view controller is a sub-controller of this view controller. (so in awakeFromNib for the WelcomeViewController use addChildViewController to make sure the movie controller is in the hierarchy).