Programmatically Create an Nsviewcontroller Without an Xib in Swift 3

Programmatically create an NSViewController without an XIB in Swift 3

A careful reading of the documentation is enlightening. Specifically:

If this property’s value is not already set when you access it, the view controller invokes the loadView() method.

Meaning, loadView() is only invoked when an attempt is made to read the view property before the property has a value. Assigning a value to the property directly will bypass the method call.

So if AppDelegate.applicationDidFinishLaunching(_:) is written like this:

    let pc = PrimaryController(nibName: nil, bundle: nil)!
print(pc.isViewLoaded)
let x = pc.view // accessing the view property before it has a value
print(pc.isViewLoaded)

...then loadView will be invoked by the system to attempt to load the view:

false
PrimaryController.loadView
false

Note that viewDidLoad() is still not invoked, since no view can be automatically associated with the controller (ie, the nib is nil and PrimaryController.xib doesn't exist). The correct way to complete the process is to manually load the view in PrimaryController.loadView():

print("PrimaryController.loadView")
view = NSView() // instantiate and bind a view to the controller

Now the program gives the desired result:

false
PrimaryController.loadView
PrimaryController.viewDidLoad
true

Initialize a subclass of NSViewController without a xib file

From the NSViewController documentation:

If you pass in a nil for nibNameOrNil then nibName will return nil and
loadView will throw an exception; in this case you must invoke
setView: before view is invoked, or override loadView.

The initializer for MyViewController() uses nil for the nibName.

Two potential fixes:

1. Set the view in your AppDelegate

func applicationDidFinishLaunching(aNotification: NSNotification) {
viewController = MyViewController()
viewController!.view = NSView() // added this line; edit to set any view of your choice
self.window.contentView!.addSubview(viewController!.view)
}

Alternately,

2. Override loadView in your subclassed ViewController

import Cocoa

class MyViewController: NSViewController {
var textField: NSTextField?

override func loadView() {
self.view = NSView() // any view of your choice
}

override func viewDidLoad() {
super.viewDidLoad()

textField = NSTextField(frame: NSRect(x: 10, y: 10, width: 100, height: 100))
textField!.bezeled = false
textField!.drawsBackground = false
textField!.editable = false
textField!.selectable = false
textField!.stringValue = "TEST"
self.view.addSubview(textField!)
}

}

macOS: How to create and launch a NSViewController without using Xib/Storyboard

The size of the view is (0, 0) and the window is resized to the fit the view. Use a bigger view:

override func loadView() {

view = NSView(frame: NSMakeRect(0, 0, 500, 500))
}

Instantiate UIViewController programmatically without nib

According to the docs:

If the view controller does not have an associated nib file, this method creates a plain UIView object instead.

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/#//apple_ref/occ/instp/UIViewController/view

If you do not provide a nib file when instantiating the view controller, UIViewController calls it's loadView() method which creates a plain UIView object and assigns it to its view property.

The reason why you are seeing a transparent view is because the UIView object has no background color. To verify this, you can set the background color of the view controller's view property right before you push it on your navigation stack.

let viewController = TestViewController()
viewController.view.backgroundColor = .blueColor()
navigationController?.pushViewController(viewController, animated: true)

Instantiating UIViewController Without A Storyboard Or xib File

init(coder aDecoder: NSCoder) is only ever called when a view is instantiated from a storyboard. To create a custom UIViewController and instantiate in manually, all you need to do is add:

required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

to your custom view controller. Now you're free to create your own initialization method and pass it whatever variables you like.

OSX application without storyboard or xib files using Swift

if you don't want to have the @NSApplicationMain attribute, do:

  1. have a file main.swift

  2. add following top-level code:

     import Cocoa

    let delegate = AppDelegate() //alloc main app's delegate class
    NSApplication.shared.delegate = delegate //set as app's delegate
    NSApplicationMain(CommandLine.argc, CommandLine.unsafeArgv) //start of run loop

    // Old versions:
    // NSApplicationMain(C_ARGC, C_ARGV)
    // NSApplicationMain(Process.argc, Process.unsafeArgv);

the rest should be inside your app delegate. e.g.:

import Cocoa

class AppDelegate: NSObject, NSApplicationDelegate {
var newWindow: NSWindow?
var controller: ViewController?

func applicationDidFinishLaunching(aNotification: NSNotification) {
newWindow = NSWindow(contentRect: NSMakeRect(10, 10, 300, 300), styleMask: .resizable, backing: .buffered, defer: false)

controller = ViewController()
let content = newWindow!.contentView! as NSView
let view = controller!.view
content.addSubview(view)

newWindow!.makeKeyAndOrderFront(nil)
}
}

then you have a viewController

import Cocoa

class ViewController : NSViewController {
override func loadView() {
let view = NSView(frame: NSMakeRect(0,0,100,100))
view.wantsLayer = true
view.layer?.borderWidth = 2
view.layer?.borderColor = NSColor.red.cgColor
self.view = view
}
}

Programmatically navigate to another view controller/scene

I already found the answer

Swift 4

let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let nextViewController = storyBoard.instantiateViewController(withIdentifier: "nextView") as! NextViewController
self.present(nextViewController, animated:true, completion:nil)

Swift 3

let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)

let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("nextView") as NextViewController
self.presentViewController(nextViewController, animated:true, completion:nil)


Related Topics



Leave a reply



Submit