Change navigation root view programmatically objective c - objective-c

I want to change the navigation's root view controller programmatically using objective c. I am using a storyboard. I tried to change it in-app delegate but didn't work, there's something new introduced called scene delegate where I believe I can change the root from there, but I found no resources for that matter. Can anyone help?

Use below code:
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = MyRootViewController()
self.window = window
window.makeKeyAndVisible()
}
}
Reference: https://www.andrewcbancroft.com/blog/ios-development/ui-work/accessing-root-view-controller-ios13-scenedelegate/
And: How set rootViewController in Scene Delegate iOS 13

Related

Load View from XIb crashes

I am loading a view using xib but it crashes always. I have tried different approaches available on net but still it crashes.I don't find any solution to deal with. I have attached code for reference Click here
I have checked your code and the problem is you would give your view class to file owner and according to it change IBOutlets and IBActions.
So first thing is Give 'CartView'to FileOwner and Remove it from View.
Then remove IBAction from gesture and IBOutlets from lbl and img then again assign which will be refer to filesowner.
What you are doing is wrong. You have set the class as Cart for both xib and the view in storyboard.
Try loading the nib from the viewController and add it as subview. If you need the small view in storyboard as a container, just create an outlet and add the card view as subview to container.
You are trying to load cart like this
private func loadViewFromNib() -> UIView {
let bundle = Bundle(for: type(of: self))
let nib = UINib(nibName: "CartView", bundle: bundle)
let nibView = nib.instantiate(withOwner: self, options: nil).first as! UIView
return nibView
}
There is absolutely no problem with loading a view with that. The problem is You should not load a view inside the view's class.
you have to do it inside a ViewController. like this:
func loadCartView() -> UIView! {
if let customView = NSBundle.mainBundle().loadNibNamed("CartView", owner: self, options: nil).first as? CartView {
customView.translatesAutoresizingMaskIntoConstraints = false
return customView
} else {
return nil
}
}
SWIFT3:
func loadCartView() -> UIView! {
if let customView = Bundle.main.loadNibNamed("CartView", owner: self, options: nil)?.first as? CartView {
customView.translatesAutoresizingMaskIntoConstraints = false
return customView
} else {
return nil
}
}

Autolayout is not working with NSSplitView and NSPageController with Storyboard. Is this Apple Bug?

I just created a empty project on github --> here <-- to demonstrate the problem (Done in objective-c)
The project is a simple storyboard project. An NSWindowController loads an NSPageController which loads a NSSplitView containing 3 panes. There is no code in the sample project, except the code to load the screens. When the project runs, it looks like this .
How do I get the constraints to make the splitView stretch all the way to the ends when the window is resized? The weird thing is, if you Switch the NSWindowController's contentController from the NSPageController to the NSSplitViewController, then every thing works as expected. Is this Apple Bug? I would appreciate any answer swift/objectivec please. I've tried but nothing works.
[EDIT] - Based on the answer below and further researching (contacted Apple), it appears that NSPageViewController does not use autolayout constraints but relies on autoresizing mask and frame setting on its children views.
So when the page controller creates its view controllers, we should set this:
-(NSViewController *)pageController:(NSPageController *)pageController viewControllerForIdentifier:(NSString *)identifier {
NSViewController *viewController = [self.storyboard instantiateControllerWithIdentifier:identifier];
[viewController.view setAutoresizingMask:(NSViewWidthSizable|NSViewHeightSizable)];
return viewController;
}
With this, the problem is fixed. I wish as an update in future, this control works with Autolayout constraints as it seems more natural.
I had many problems with NSPageController. I found that the solution is to not use auto layout with it.
Try to use the NSAutoresizingMaskOptions on your NSSplitView.
First, remove all constraints inside the NSPageController.
Then:
splitView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
splitView.frame = pageController.view.bounds;
or
splitView.autoresizingMask = [.ViewWidthSizable, .ViewHeightSizable]
splitView.frame = pageController.view.bounds
EDIT
Made a project based on yours here
I also got same issue in Pagecontroller:
And solved it by using the given code:
func pageController(_ pageController: NSPageController, viewControllerForIdentifier identifier: String) -> NSViewController {
switch identifier {
case "formController":
let controller = NSStoryboard(name: "Main", bundle:nil).instantiateController(withIdentifier: "formController") as! FormController
controller.view.autoresizingMask = [.height , .width]
return controller
default:
return self.storyboard?.instantiateController(withIdentifier: identifier) as! NSViewController
}
}
func pageController(_ pageController: NSPageController, identifierFor object: Any) -> String {
return String(describing: object)
}
func pageControllerDidEndLiveTransition(_ pageController: NSPageController) {
print(pageController.selectedIndex)
pageController.completeTransition()
pageController.selectedViewController!.view.autoresizingMask = [.height , .width]
}

Segue between UIViewControllers without Storyboard OR XIB

I have a nifty project I downloaded from GitHub (here) and I am playing around with it. The project has no storyboard or xibs whatsoever, and only one viewController, which is defined with just a viewController.h file and a viewController.m file.
Perhaps a noob question, but can I have viewController1.h/m programmatically segue to viewController2.h/m without using ANY xibs or storyboards? I found a lot of code on SO and elsewhere allowing one to segue programmatically from one view to another within a Storyboard, from one xib to another or from a scoreboard to a xib (though not the opposite) but nothing on how to segue from one totally code-based vc to another. All the code I found requires that you define the view in terms of the bundle location of the storyboard or xib file, but I want to use neither.
Note: I accepted the answer I did because of its ingenuity/interesting-ness, but for the sake of simplicity I personally ended up opting with this answer to the same question (mine was a duplicate it appears): iOS: present view controller programmaticallly
You can use [viewController presentViewController:anotherController animated:YES completion:nil]; to present the view controller modally.
Another alternative is to use a UINavigationController and do [viewController.navigationController pushViewController:anotherController animated:YES];
The second method will only work if viewController is in the stack of a navigationController
Here is my Context class which changes view controllers. It works with either your own view classes or storyboard view classes.
Specific to your question look at the open function. If there is no root controller when I call open, I assign it as the root view controller. Otherwise I present it from the root view controller.
import Foundation
import UIKit
private let _StoryBoard = UIStoryboard(name: "Main", bundle: nil)
private let _RootWindow = UIWindow(frame: UIScreen.mainScreen().bounds)
public var ROOT_VIEW_CONTROLLER:UIViewController = C_RootViewController()
//abstract base of context classes
class Context:NSObject
{
class var STORYBOARD:UIStoryboard
{
return _StoryBoard
}
class var ROOTWINDOW:UIWindow
{
return _RootWindow
}
var _currentController:Controller!
class func reassignRootViewController(controller:UIViewController)
{
Context.ROOTWINDOW.rootViewController = controller
ROOT_VIEW_CONTROLLER = controller
}
func initController(controllerName:String)->Controller
{
return Context.STORYBOARD.instantiateViewControllerWithIdentifier(controllerName) as Controller
}
func initControllerFromStoryboard(storyboardName:String,controllerName:String)->Controller
{
var storyboard:UIStoryboard = UIStoryboard(name: storyboardName, bundle: nil)
return storyboard.instantiateViewControllerWithIdentifier(controllerName) as Controller
}
func open(controller:UIViewController)
{
if(Context.ROOTWINDOW.rootViewController == nil)
{
Context.ROOTWINDOW.rootViewController = ROOT_VIEW_CONTROLLER
Context.ROOTWINDOW.makeKeyAndVisible()
}
ROOT_VIEW_CONTROLLER.presentViewController(controller, animated: true, completion: {})
}
func close(controller:UIViewController)
{
ROOT_VIEW_CONTROLLER.dismissViewControllerAnimated(true, completion: nil)
}
}

XCode doesn't load a custom view

I have created a custom view for an error message.
I created an ErrorView.swift sub classing UIView and I created also an ErrorView.xib to use in Interface Builder.
In the identity inspector I set the custom class of the xib as ErrorView.swift but
when I try to load this specific view it doesn't work.
Why? Can you help me?
This is the code:
My personalized class named ErrorView
Class ErrorView: UIView {
class func errorInView(view:UIView, animted:Bool) -> ErrorView {
println("ERROR VIEW LOADED")
let errorView = ErrorView(frame: view.bounds)
errorView.opaque = false
view.addSubview(errorView)
return errorView
}
}
my xib:
http://i59.tinypic.com/23tnlev.png
This is the code I use in my ViewController to call the view.
let errorView = ErrorView.errorInView(self.view, animted: true)
The problem here is that you are not loading your xib, instead you are creating a new Error View in code.
If you add errorView.backgroundColor = UIColor.greenColor() after errorView is created, but before you add it as a subview you will see the screen turn green. I have posted this example as a gist.
If you want to create your view from the xib you will have to load the xib using the normal NSBundle.mainBundle() call.
let errorView = NSBundle.mainBundle().loadNibNamed("ErrorView", owner: self, options: nil)[0] as ErrorView
instead of creating the view with the ErrorView(frame:)
This example is also a gist.

Initializing another window using storyboard for OS X

I have created a Cocoa application in Xcode6 which uses storyboards. As a template, Xcode provides a window for the application. I want to add a second window to show when the program is first loaded. So basically, there will be two windows showing up.
I have put a window controller on Main.storyboard where the first window also resides. However, I couldn't find the way to show this second window when the program starts. Could you please help?
Thank you.
In your Storyboard, select your second Window Controller. In the identity inspector, specify a name for this window controller, e.g secondWindowController
Then, in your app delegate, set up a property for the window controller:
#property NSWindowController *myController;
In your applicationDidFinishLaunching: method implementation, create a reference to the Storyboard. This way you get access your window controller from the storyboard.
After that, the only thing left to do is to display the window by sending your window controller the showWindow: method.
#import "AppDelegate.h"
#interface AppDelegate ()
#end
#implementation AppDelegate
#synthesize myController;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
NSStoryboard *storyBoard = [NSStoryboard storyboardWithName:#"Main" bundle:nil]; // get a reference to the storyboard
myController = [storyBoard instantiateControllerWithIdentifier:#"secondWindowController"]; // instantiate your window controller
[myController showWindow:self]; // show the window
}
#end
Swift 3 version:
var myWindowController: NSWindowController!
override init() {
super.init()
let mainStoryboard = NSStoryboard.init(name: "Main", bundle: nil)
myWindowController = mainStoryboard.instantiateController(withIdentifier: "myWindowControllerStoryboardIdentifier") as! NSWindowController
myWindowController.showWindow(self)
}
Make sure you define myWindowController outside the function or else the window won't show up.
It's actually better to do this in init() (of AppDelegate) as you may need it earlier on.
Swift 5:
The project setup in XCode 13 has entirely changed. There is no longer an example of how to connect to the storyboard from the AppDelegate. Instead, they are hardcoding a NSWindow. I still find Storyboards useful, hence the below should come in handy. Remember to name your WindowController in Storyboard as mainWindowController.
let mainStoryboard = NSStoryboard.init(name: NSStoryboard.Name("Main"), bundle: nil)
var monitorcontroler = mainStoryboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("mainWindowController")) as! NSWindowController
monitorcontroler.showWindow(self)
swift 4 version :
var monitorcontroler: NSWindowController!
override init() {
super.init()
let mainStoryboard = NSStoryboard.init(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil)
monitorcontroler = mainStoryboard.instantiateController(withIdentifier: NSStoryboard.SceneIdentifier(rawValue: "moniteur")) as! NSWindowController
monitorcontroler.showWindow(self)
}