since I've been unable to do even one succesfull merge with storyboard, I'm trying to switch to xib files. I'm trying to set one xib file as initialViewController as you do in storyboard, so first I've disabled that property in storyboard. Following some examples from google, I've made an extension that is supposed to return a xib file:
extension UIViewController {
class func loadFromNibNamed(nibNamed: String, bundle : NSBundle? = nil) -> UIViewController? {
return UINib(
nibName: nibNamed,
bundle: bundle
).instantiateWithOwner(nil, options: nil)[0] as? UIViewController
}
and then called that class function from the app delegate and try to load the xib file as root view controller like this:
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
let mainView = UIViewController.loadFromNibNamed("MainView")
//window?.addSubview(mainView!)
self.window?.rootViewController = mainView
return true
}
My xib file name is MainView.xib, I have a UIView and a MainViewController on it, MainViewController inherits from ViewController and it's still empty:
Whatever I try I allways get the same error message:
Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?
You still have the project set up to use the Main.storyboard file. In the project / general tab, you need to clear this section:
If you do this you will also need to create the UIWindow yourself and set the app delegate's window property, as this is not created if you don't use a storyboard. See How to create an Empty Application in Xcode 6 without Storyboard for details.
Related
A swift iOS app has 3 targets - AppTarget, Main (static lib which contains the entry point i.e. AppDelegate) and Presentation (static lib which contains UI code). AppTarget depends on Main and Presentation. Presentation depends on Main.
Question is, how do I set the UIWindow variable in Main from Presentation?
#main
public class AppDelegate: UIResponder, UIApplicationDelegate {
// UIWindow view of UIApplicationDelegate protocol
var window : UIWindow?
...
}
I tried two approaches:
Approach1:
Directly access the UIWindow variable using the AppDelegate object, but it gives 'Cannot assign to property: 'shared' is a get-only property' error:
UIApplication.shared.delegate?.window = UIWindow() // Error: Cannot assign to property: 'shared' is a get-only property
Approach2:
Use an intermediate static variable like:
// In AppDelegate,
static var keyWindow : UIWindow? = nil
public func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Set UIWindow variable to the static instance.
window = AppDelegate.keyWindow
// Now, instantiating AppDelegate.keyWindow is the same as instantiating window (?).
...
return true
}
// Elsewhere, in Presentation,
func CreateWindow() {
window = AppDelegate.keyWindow
AppDelegate.keyWindow = UIWindow()
AppDelegate.keyWindow?.rootViewController = ViewController()
AppDelegate.keyWindow?.makeKeyAndVisible()
}
// ViewController has a simple UI
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .systemGreen
}
}
This gives me a black screen, meaning, there's no UI...an empty screen. But I expected to see a green screen.
I understand that UI has to be set in the UIWindow variable of the AppDelegate (if you use another UIwindow variable, its contents are not displayed and you'd get an empty black screen), due to its conformance to UIApplicationDelegate protocol.
How can I achieve this elegantly?
Note1: Assume I've opted out of scenes
Note2: Ignore how AppDelegate in Main invokes CreateWindow() in Presentation, but it somehow does.
So, I'm trying to instantiate my view controller programmatically using storyboard references.
I've put this code in the AppDelegate:
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
window = UIWindow(frame: UIScreen.main.bounds)
let mainStoryboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let initialController: WelcomePageViewController = mainStoryboard.instantiateViewController(withIdentifier: "WelcomePageViewController") as! UITabBarController
window?.rootViewController = initialController
window?.makeKeyAndVisible()
return true
}
And set this inside my view controller's storyboard:
However when I run the application, only a black screen is shown and this message:
"Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?"
I've used this exact code in other apps and it works just fine.
I've tried to clean build folder, to run it on an actual device and to create and instantiate a different storyboard file but nothing worked.
Open your Main.storyboard file and find WelcomePageViewController. When it’s selected, go to the attributes inspector and check the box marked Is Initial View Controller.
You should see a right-facing arrow appear to the left of WelcomePageViewController, showing that it’s your storyboard’s entry point.
Now you're all set to go!!!
Ok So i think here is something you can do if it suits:
set entry point to the navigation controller
class that navigation controller with a file like rootNavigationVC.swift which is subclass of UINavigationController
now in didLoad() you can set it's viewController or push one based on your condition
trust me its better than coding in AppDelegate.swift which never worked for me.
This question already has an answer here:
Xcode 11 & iOS13, using UIKIT can't change background colour of UIViewController
(1 answer)
Closed 3 years ago.
I am trying to programmatically set the initial View controller but i keep getting this Error. Any solutions?
2019-11-07 11:47:43.975990+0000 RestaurantApp[16319:147412] [WindowScene] Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?
Here is the code that i have Written.
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
let window = UIWindow()
let locationService = LocationService()
let storyboard = UIStoryboard(name: "Main", bundle: nil) //refernce to our storyboard
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
//setiing the root view control on our window
switch locationService.status {
case .notDetermined, .denied, .restricted:
let LocationViewController =
storyboard.instantiateViewController (withIdentifier: "LocationViewController") as? LocationViewController
LocationViewController?.locationService = locationService
window.rootViewController = LocationViewController
default:
assertionFailure()
}
window.makeKeyAndVisible()
return true
}
}
Here is an Image of my storyboard
iOS 13 has moved the windows setup from AppDelegate to SceneDelegate to support the use of (possibly multiple) scenes rather than a single window. You now have to do the setup like this:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
let storyboard = UIStoryboard(name: "Main", bundle: nil)
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let windowScene = scene as? UIWindowScene else { return }
let vc = storyboard.instantiateViewController (withIdentifier: "Primary") as! ViewController
window = UIWindow(windowScene: windowScene)
window?.rootViewController = vc
window?.makeKeyAndVisible()
}
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let homeView = storyboard.instantiateViewController(withIdentifier: "ViewController") as! ViewController
self.window?.rootViewController = homeView
return true
}
this works for me
This error happens due to a simple mistake in your storyboard, and it’s easy to fix. When your app starts, iOS needs to know precisely which view controller needs to be shown first – known as your default view controller.
If you accidentally deleted that view controller, or otherwise made it not the default, then you’ll see the error “Failed to instantiate the default view controller for UIMainStoryboardFile 'Main' - perhaps the designated entry point is not set?” when your app launches, along with a plain black screen.
To fix the problem, open your Main.storyboard file and find whichever view controller you want to be shown when your app first runs. When it’s selected, go to the attributes inspector and check the box marked “Is Initial View Controller”. You should see a right-facing arrow appear to the left of that view controller, showing that it’s your storyboard’s entry point.
Go back to storyboard and checkmark this to make the viewController you want your app to start off to,
I wish to create and present a view over each view controller in my app allowing users to interact with it or the view controllers beneath it. I want the view to always appear on top of whatever view I may present or segue to.
I have a custom UIView that appears when users tap a table view cell. Within the didSelectRowAt tableView function I have tried:
(UIApplication.shared.delegate as! AppDelegate).window?.addSubview(self.subView!)
and
self.view.addSubview(self.subView!)
Both function similarly with the view appearing over the current View controller and allowing users to interact with the table still. But when I present a new ViewController the subView disappears as it has not been added to the new View.
Subclass UIWindow, and override addSubview() to make sure your overlay view is always on top:
weak var overlay: MyOverlayView!
override func addSubview(_ view: UIView) {
if let overlay = view as? MyOverlayView {
self.overlay = overlay
super.addSubview(overlay)
} else {
self.insertSubview(view, belowSubview: overlay)
}
}
You must make sure the app delegate uses your custom class as the app's main window, and not the superclass UIWindow. For this, remove the "Main storyboard file base name" entry from your Info.plist and instead instantiate the main window manually in your AppDelegate:
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: MyCustomWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil) -> Bool {
self.window = MyCustomWindow(frame: UIScreen.main.bounds)
// 1. Add your overlay view to the window
// (...)
// 2. Load your initial view controller from storyboard, or
// instantiate it programmatically
// (...)
window?.makeKeyAndVisible()
return true
}
Note: I haven't tested this code. Let me know in the comments if there's a problem.
I've been trying for days to get UISplitViewController to call the delegate. I tried setting it in the MasterViewController, I tried setting it in the DetailViewController, I tried having the SVC as an embedded view controller in a container inside another view controller, and use the prepareForSegue call to set the delegate. I tried instantiating it from the Storyboard in the AppDelegate and setting the delegate there. The delegate is never ever called. I'm going crazy.
I'm on the latest non-beta Swift (3.1), on iOS 10.3.1.
I've used the Debugger to check the delegate is in fact set, and remains in memory, however, the methods are never called.
I appreciate any help you can provide me with.
This is my current AppDelegate but I've tried countless ways as I said:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
Realm.Configuration.defaultConfiguration.deleteRealmIfMigrationNeeded = true
if let svc = self.window?.rootViewController as? UISplitViewController {
svc.delegate = svc.viewControllers.last as! UISplitViewControllerDelegate
}
return true
}
Edit 1:
Some of you didn't understand what delegate I'm trying to implement. To clarify, I'm trying to control the delegate of UISplitViewController, in other words, the UISplitViewControllerDelegate. The reason I'm trying to do this is to be able to control the collapsing of views. In the default configuration of the UISplitViewController, on an iPhone on portrait mode, it defaults to the detailViewController. This behavior is clearly wrong for most apps (and mine). I intend to first show the masterViewController that lists the content I have for display, and trigger the detailViewController only when an item has been selected.
I would also accept an answer that gave me some alternative way to have that behavior (prefer masterViewController on portrait unless my detailViewController has content set.
I know you can get the described behavior by not setting a detailViewController in the Storyboard, and using the showDetail segue when selecting an item, but my problem with that is I can't have a default view when no item has been selected, causing a grey square being shown (not very pretty) when in landscape on an iPad or iPhone Plus.
Please try below code it's work for me.
In AppDelegate:
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
let splitViewController = self.window!.rootViewController as! UISplitViewController
let navViewController = splitViewController.viewControllers.first as? UINavigationController
let masterVC = navViewController?.topViewController as? MasterViewController
let detailViewController = splitViewController.viewControllers.last as? DetailsViewController
masterVC?.delegate = detailViewController
return true
}
In MasterViewController
protocol MasterViewControllerDelegate : class{
func passingData(strName : String)
}
class MasterViewController: UITableViewController {
weak var delegate : MasterViewControllerDelegate?
override func viewDidLoad() {
super.viewDidLoad()
//Calling Delegate
delegate?.passingData(strName: "Any Message")
if let detailViewController = self.delegate as? DetailsViewController {
splitViewController?.showDetailViewController(detailViewController, sender: nil)
}
}
}
In DetailViewController
class DetailsViewController: UIViewController, MasterViewControllerDelegate{
//Other IBOutlet and Methods
//Delegate method of MasterViewControllerDelegate
func passingData(strName : String)
print(strName) //OUTPUT: "Any Message"
}
}
I hope it also work for you.