I'm working through this tutorial from apple. I am getting stuck on the shown below, I keep getting an error, Use of unresolved identifier 'window'
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let splitViewController = window!.rootViewController as! UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem
// Add a translucent background to the primary view controller.
splitViewController.primaryBackgroundStyle = .sidebar
splitViewController.delegate = self
return true
}
any suggestions?
It is simple. Catalyst apps are by default Window Scene-based. You don’t have a window here. Apple tutorials are outdated.
The solution is to create your own window and fill it in didFinish...
The more correct way is to add your code to delegate of scenes.
Related
I am a new iOS programmer and I am trying to make an application that involves the following flow:
-> UITabBar -> UINavController -> UITableViewController.
Initially the program was working when I have the following flow:
-> UINavController -> UITableViewController
But when I added the UITabBar (with the Embed In method)the I had two issues:
1) Casting the initial view from UITableView to UITabBarView
2) The data which have been restored from Archives of the phone are not loading in the TableView.
I managed to fix the casting issue with the UIStoryboard IDs, but I am not sure if this way I created the second problem of not passing data to the UITableView correctly.
The Casting problem has taking place at the appDelegate code. Here is the original code I had before incorporating the UITabBarView:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let navController = window!.rootViewController as! UINavigationController
let SLBprojectController = navController.topViewController as! GR8TableView
SLBprojectController.SLBprojectDB = thisSLBprojectDB
return true
}
The problem with the above code was that it told me that it could not cast a TableViewController (GR8TableView) into a UITabBarView. I have managed to fix this by searching in the StackOverflow forums by making the following:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
let mainStoryboardIpad : UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarIntial : UITabBarController = mainStoryboardIpad.instantiateViewController(withIdentifier: "TabBar") as! UITabBarController
let navigationController:UINavigationController = mainStoryboardIpad.instantiateViewController(withIdentifier: "navController") as! UINavigationController
let navigationController1:UIViewController = mainStoryboardIpad.instantiateViewController(withIdentifier: "ViewController1")
let SLBprojectController = navigationController.topViewController as! GR8TableView
SLBprojectController.SLBprojectDB = thisSLBprojectDB
tabBarIntial.viewControllers = [navigationController, navigationController1]
tabBarIntial.selectedIndex = 0
return true
}
But after I fixed the "casting" issue then I am getting problems loading the data in the TableView. Not sure if this problem is related to the way I fixed the casting issue.
Any assistance would be much much appreciated!
The simplest answer would be to go back to logic similar to what worked for you, but with a slightly more complex relationship. For example, I created an app with a tab bar controller, a navigation controller in the first tab, and a FirstViewController embedded in the navigation controller.
Since I don't have a database, I gave the FirstViewController a single instance variable called running.
The following code finds the controller and sets the variable:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
if let tabController = window!.rootViewController as? UITabBarController {
if let navController = tabController.viewControllers![0] as? UINavigationController {
if let firstController = navController.topViewController as? FirstViewController {
firstController.running = true
} else {
print("Unexpected controller in navigation hierarchy: \(String(describing: navController.topViewController))")
}
} else {
print("Unexpected contained controller: \(String(describing: tabController.viewControllers![0]))")
}
} else {
print("Unexpected root controller: \(String(describing: window!.rootViewController))")
}
return true
}
Note that I'm not creating any new controllers. That's all done by default storyboard loading.
I believe you should be able to adapt this to your own variable and class names.
tried to pass data between view controllers,but keeps getting the error:
Could not cast value of type 'UIViewController' (0x10b4e4ca8) to 'StockList.AllListsTableViewController' (0x106d963f0).
I have checked to make sure that I set the classes for the view controllers but it's still not working.Here is my code:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let navigationController = window!.rootViewController as! UITabBarController
let controller = navigationController.viewControllers![0] as! AllListsTableViewController
controller.dataModel = dataModel
return true
}
Here is my storyboard:
Thanks in advance
First make sure to set class name to the VC in IB from Identity Inspector ( AllListsTableViewController )
Second use
let tab = window!.rootViewController as! UITabBarController
let navigation = tab.viewControllers![0] as! UINavigationController
let controller = navigation.viewControllers![0] as! AllListsTableViewController
controller.dataModel = dataModel
I am a self-taught newcomer to iOS programming and have worked through one beginner textbook. I'm trying to publish my first mobile application so I am going back through and cleaning up my code. The textbook I used stressed 'Dependency Injection' but I've struggled adapting their simple example to a more complex application.
The app operates as a shell and retrieves/parses txt files to populate. I successfully connected my model, which retrieves/parses the data, and the TableViewController that needs populated using the following code:
MyTableViewController {
var data: Data!
}
AppDelegate {
var window: UIWindow?
let data = Data()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let navCon = window!.rootViewController as! MyNavigationController
let tableVC = navCon.topViewController as! MyTableViewController
tableVC.data = data
return true
}
I then embedded that NavigationController within a TabBarController because the app will have other tabs. I tried the same process of setting the rootViewController and then drilling down until I could set my data variable, but I can't find the correct way to layer the ViewControllers and keep getting the error;
'fatal error: unexpectedly found nil while unwrapping an Optional value'
I tried two different approaches:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let tabBarCon = window!.rootViewController as! MyTabBarController
let navCon = tabBarCon.presentedViewController as! MyNavigationController
let tableVC = navCon.topViewController as! MyTableViewController
tableVC.data = data
return true
}
and
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let tabBarCon = window!.rootViewController as! MyTabBarController
let navCon = MyNavigationController()
tabBarCon.viewControllers = [navCon]
let tableVC = navCon.topViewController as! MyTableViewController
tableVC.data = data
return true
}
Is there a solution to correct this error or am I going about this process wrong? Again, I have a file that pulls in a txt file and then creates a dictionary. I need a separate TableViewController to be able to access that dictionary to populate itself, but I want to achieve this in the most efficient and apple promoted manner, not all in the same file as I did in my first design.
Thanks for the help!
For Dependency Injection I do recommend you use Typhoon. From mine experience it's one of the best tool. This will help you to achive app asembly like:
/*
* This is the definition for our AppDelegate. Typhoon will inject the specified properties
* at application startup.
*/
public dynamic func appDelegate() -> AnyObject {
return TyphoonDefinition.withClass(AppDelegate.self) {
(definition) in
definition.injectProperty("cityDao", with: self.coreComponents.cityDao())
definition.injectProperty("rootViewController", with: self.rootViewController())
}
}
I found the solution through this thread;
Aassigning a value to a view controller from AppDelegate.swift
The result can be achieved by reconfiguring the second solution I attempted;
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let tabBarCon = window!.rootViewController as! MyTabBarController
let tabBarRootVCs: Array = tabBarCon.viewControllers!
let navCon = tabBarRootVCs[0] as! MyNavigationController
let tableVC = navCon.topViewController as! MyTableViewController
tableVC.data = data
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.
I have searched much but with no success. I am attempting to access the TableView of the splitViewController from AppDelegate.swift. How do I do this?
This is the standard code that Apple supplies when starting a new project for a Split View Controller:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let splitViewController = self.window!.rootViewController as! UISplitViewController
let navigationController = splitViewController.viewControllers[splitViewController.viewControllers.count-1] as! UINavigationController
navigationController.topViewController!.navigationItem.leftBarButtonItem = splitViewController.displayModeButtonItem()
splitViewController.delegate = self
return true
}
Or perhaps it is not possible? Which I cannot believe :-)