i'm using xcode 6 and they no longer have the "empty project" option when creating a new project, only a single view one...Is there an option to get it or it's gone and I need to deal with it?
Thanks a bunch
You need to deal with it, but it's easy. Start with the Single View application. Delete the storyboard and delete the reference to it in the Info.plist (so that there is no longer a main storyboard). If you like, delete the view controller class as well. Now just do everything from scratch in the app delegate's application:didFinishLaunchingWithOption:, just as you did in Xcode 5.
I'm using Swift these days, so I'll show you what a pure code app delegate launch looks like in Swift; I'm sure you can translate into Objective-C:
import UIKit
#UIApplicationMain
class AppDelegate : UIResponder, UIApplicationDelegate {
var window : UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
self.window = UIWindow(frame:UIScreen.mainScreen().bounds)
self.window!.rootViewController = ViewController() // or whatever you call it
self.window!.backgroundColor = UIColor.whiteColor()
self.window!.makeKeyAndVisible()
return true
}
}
Related
Edit: Not sure if I can mark a question as solved but it was thanks to Alex. It was an issue with the newest version of Xcode but instructions meant for an older one. Moving the code fragments from AppDelegate to SceneDelegate fixed it.
I'm very new to Xcode and IOS app development. I'm taking my first course and we receive "guided labs" where we follow step by step instructions and copy paste bits of code to create an app. Following the instructions, I've gotten stuck at a certain spot and have tried googling/ researching to no avail.
The app is called Restaurant and essentially allows a user to look at a menu (see items/ pricing/ details) and add certain items to an order, which then shows in another tab called "Your Order". Those parts have been completed but the step I'm on is "to update the badge value of the Order tab to match the number of items in the order. Then the user can see that they've successfully added an item without needing to switch tabs." The UITabBarItem is an optional as stated in the instructions inside AppDelegate but is nil.
This line produces the error: Thread 1: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
The error trail seems to originate in updateOrderBadge() specifically with adjusting the orderTabBarItem being the main issue. Commenting out that single line, everything runs although of course I don't get the desired badge notification. Not sure why that line which comes directly from the guide is having issues:
#objc func updateOrderBadge() {
orderTabBarItem.badgeValue = String(MenuController.shared.order.menuItems.count)
}
I've seen this or a similar error before when I forgot to connect IBOutlets/ Actions from button to code, is there supposed to be something like that for UITabBarItem?
For some overall context, here are the instructions and the code in screenshots:
Screenshot of specific lab instructions that I thought I followed step by step/ copy and pasted directly
A screenshot of the storyboard for context
Code inside AppDelegate that I'm altering
Otherwise here is the code in app delegate in text:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var orderTabBarItem: UITabBarItem!
#objc func updateOrderBadge() {
orderTabBarItem.badgeValue = String(MenuController.shared.order.menuItems.count)
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow()
orderTabBarItem = (self.window?.rootViewController as? UITabBarController)?.viewControllers?[1].tabBarItem
NotificationCenter.default.addObserver(self, selector: #selector(updateOrderBadge), name: MenuController.orderUpdatedNotification, object: nil)
return true
}
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
}
}
It seems like you're using Xcode 11 for your project, which is why you have a SceneDelegate.swift file in your project, and UIScene-related methods in your AppDelegate.swift file.
By default the template in Xcode 11 is using a SceneDelegate and all the related methods that came with iOS 13, so the app launch process differs a lot from the one in iOS 12.
In iOS 13, the window is no longer a property of the AppDelegate, but is instead managed by default by the SceneDelegate.
I think the project for the course you're following now, has been created with an earlier version of Xcode, which is why they're asking you to add a window property in AppDelegate, and initialize it in didFinishLaunchingWithOptions method, and the problem is that this is not the correct way to do it anymore in iOS 13.
So long story short, by default the app delegate now uses the default scene configuration, and the scene delegate is responsible for setting the UIWindow object via the scene(_:willConnectTo:options:) delegate method. By default, it uses the Main.storyboard to create your first screen.
In your case to solve your problem, you would simply need to access the window property from the scene(_:willConnectTo:options:) delegate method of the SceneDelegate like so:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
var orderTabBarItem: UITabBarItem!
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let _ = (scene as? UIWindowScene) else { return }
orderTabBarItem = (self.window?.rootViewController as? UITabBarController)?.viewControllers?[1].tabBarItem
}
// ...
}
If you want to make your project compatible for iOS 12 as well (and keep a window property in the AppDelegate), you could also do that, but I would not recommend.
Anyway, you can find more interesting information at the link below, which shows the difference between the old launch process, and the new launch process, and more importantly explains how you can set up the new launch process in iOS 13, whether you decide to use Storyboards or not:
https://learnappmaking.com/scene-delegate-app-delegate-xcode-11-ios-13/#using-scene-delegate-with-storyboards
Feel free to ask if you still have a doubt, and good luck for your course :)
You seem to have missed a step where window is initialized. Try initializing the window inside didFinishLaunchingWithOptions method. Also, add the observer after the orderTabBarItem is set. Like this:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow()
if let tabBarController = window?.rootViewController as? UITabBarController {
if let tabBarItem = tabBarController.viewControllers?[1].tabBarItem {
orderTabBarItem = tabBarItem
print("Successfully set orderTabBarItem")
} else {
print("TabBarController didn't have any viewControllers")
}
} else {
print("rootViewController isn't a UITabBarController")
}
NotificationCenter.default.addObserver(self, selector: #selector(updateOrderBadge), name: MenuController.orderUpdatedNotification, object: nil)
return true
}
I have created the iOS Project in Xcode 11.1. I need to remove scene delegate from the application.
You need to do the following steps:
Remove Scene delegate methods from App Delegate and delete the Scene delegate file.
You need to remove UIApplicationSceneManifest from Info.plist.
You also need to add var window:UIWindow? if it is not present in AppDelegate
Remove SceneDelegate.swift file
Remove Application Scene Manifest from Info.plist file
Add var window: UIWindow? to AppDelegate.swift
Replace #main with #UIApplicationMain
Remove UISceneSession Lifecycle ( functions ) in AppDelegate
It is a complete solution for empty project generated with Xcode (with storyboard)
Remove SceneDelegate.swift file
Remove Application Scene Manifest from Info.plist file
Paste this code to your AppDelegate.swift file
import UIKit
#main
class AppDelegate: UIResponder, UIApplicationDelegate {
var window:UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
self.window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = UIStoryboard(name: "Main", bundle: nil).instantiateInitialViewController()
window?.makeKeyAndVisible()
return true
}
}
Adding on to milzi's answer
Remove SceneDelegate.swift file
Remove Application Scene Manifest from Info.plist file
Remove UISceneSession Lifecycle function from your AppDelegate class
Add var window: UIWindow? in your AppDelegate class as a instance property
Replace #main attribute with #UIApplicationMain attribute (This saves as to manually create and assign window)
Below is how you how your AppDelegate should look like after changes:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
}
To add to accepted answer: you also need to write this in your AppDelegate:
self.window = UIWindow(frame: UIScreen.main.bounds)
let controller = MyRootViewController()
window?.rootViewController = controller
window?.makeKeyAndVisible()
Just in case if you are developing in Objective-C, add window property in the AppDelegate.h file like this:
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
No need to initialise the window. It will work automatically.
My console posted this error today, [ApplicationLifecycle] UIWindows were created prior to initial application activation. This may result in incorrect visual appearance.
This has caused Application UI to not behave properly. I have never seen this before and need some insight on where to start debugging.
macOS: Catalina 10.15
XCode version: Version 11.1
I think that apps main UIWindow should be lazily initiated. Try with this:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var window: UIWindow? = UIWindow(frame: UIScreen.main.bounds)
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window?.rootViewController = RootViewController() // root view controller
window?.makeKeyAndVisible()
return true
}
}
I am learning how to create an iOS app without Interface Builder (i.e. storyboards, xibs, etc.). Below is the basic app delegate class I am working with. The problem is that when displayed the UIWindow does not use up the full screen of the device (see attached screenshot). This occurs on all the devices and simulators I test with. Why isn't the fullscreen being used?
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
lazy var window: UIWindow? = {
debugPrint("AppDelegate: Creating Window")
let screen: UIScreen = UIScreen.mainScreen()
let window: UIWindow = UIWindow.init(frame: screen.bounds)
window.backgroundColor = UIColor.whiteColor()
return window
}()
lazy var rootViewController: ShapesViewController = {
debugPrint("AppDelegate: Creating Root View Controller")
let rootViewController = ShapesViewController.init(nibName: nil, bundle: nil)
return rootViewController
}()
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
debugPrint("AppDelegate: applicationWillEnterForeground")
window?.rootViewController = rootViewController
window?.makeKeyAndVisible()
return true
}
}
The problem turned out to be that I did not have a launch image or storyboard. For some reason without this the app defaults to the 3.5" size. Credit to this comment: A launch storyboard or xib must be provided unless the app requires full screen
This always works for me (I don't see any clear difference though). Do you mind sharing your ShapesViewController code as well?
Updated to swift 4.2
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
window?.rootViewController = ViewController()
window?.makeKeyAndVisible()
return true
}
I know sounds silly but...
For a fresh project what macinjosh is saying works.
For a project of mine in Xcode 8 and swift 3, it didn't (probably because I deleted the launch screen and had to create again).
Just created new project fresh, and follow what macinjosh said. Then migrate all your files back in.
This warning message happens on both iOS 8 and 9 devices as well as simulator:
[Warning: Unable to create restoration in progress marker file]
It only shows once when I first launch (With first installation) the app. Any subsequent launch of this app from Xcode without uninstalling it will NOT show this warning message.
Is this normal for my app? This is what I did to my code:
AppDelegate.swift:
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
return true
}
func application(application: UIApplication, willFinishLaunchingWithOptions launchOptions: [NSObject : AnyObject]?) -> Bool {
return true
}
func application(application: UIApplication, shouldSaveApplicationState coder:NSCoder) -> Bool{
return true;
}
func application(application: UIApplication, shouldRestoreApplicationState coder:NSCoder) -> Bool{
return true;
}
}
The Restoration ID is purely done in Main.storyboard, such that RestorationID and StoryboardID are the same. And also, only top level of View has the same RestorationID as the StoryboardID.
In the default created tabbed view application, I applied the following onto both my controllers (With the second controller named as "SecondView" instead)
StoryboardID and RestorationID are the same
Top View has the RestorationID same as the StoryboardID
Meanwhile, what will happen if I simply set the following functions as false:
func application(application: UIApplication, shouldSaveApplicationState coder:NSCoder) -> Bool{
return true;
}
func application(application: UIApplication, shouldRestoreApplicationState coder:NSCoder) -> Bool{
return true;
}
Will my application still work even when it requires extended period of time in lock screen or background?
FYI. this fixed my problem: https://stackoverflow.com/a/20157399/49748
If this warning still occurred, you could check how you run your app in Xcode. I ran my app in Xcode simulator and had to follow a specific sequence to trigger state preservation.
launch the app in Xcode simulator
In Xcode simulator, click the "Home" button to put the app into the background. The encodeRestorableStateWithCoder method of the view controller should be called
go back to Xcode, click the "stop" button to terminate the simulation
In Xcode simulator, double click the "Home" button and then remove the app from the app switcher and
go back to Xcode, run the app again.