Why is drawRect not called in the NSView when I programmatically load my window from a storyboard? - swift

I have a window in my Main.storyboard file that I am trying to load programmatically, and not at application launch. So I have deleted the "Storyboard Entry Point" entirely, and in AppDelegate.swift, I have:
let storyBoard = NSStoryboard(name: "Main", bundle: nil)
let pauseWindowController = storyBoard.instantiateControllerWithIdentifier("pauseWindowController")
pauseWindowController.showWindow(self)
This seems to work, but when I run the app, I get no window. I added tracing code in my app to follow the progression of events, and I find that my custom NSView subclass is initialized, but drawRect is never called. If I remove the above code above and re-add the Storyboard Entry Point (to point to the window controller), everything works fine.
Here is the result of my print calls that I added for tracing, which show the calling class and the method called:
(AppDelegate) applicationDidFinishLaunching
(Pause OverlayWindow : NSWindow) Window init
(PauseOverlayView : NSView) View init
(PauseViewController: NSViewController) viewDidLoad
(PauseViewController: NSViewController) viewDidAppear
(PauseViewController: NSViewController) viewWillDisappear
(PauseViewController: NSViewController) viewDidDisappear
There should be a line (PauseOverlayView : NSView) drawRect line after viewDidAppear, and the window should display, but the method is never called. Why?
I have "Visible At Launch" checked in the Storyboard editor for my window. To my understanding, drawRect is called if the view is dirty and visible. I imagine it's not visible for some reason, but can't find out why.

I found my mistake: I didn't add the pauseWindowController property (var pauseWindowController : NSWindowController!) to the top of my AppDelegate.swift file. And the code should then become
let storyBoard = NSStoryboard(name: "Main", bundle: nil)
pauseWindowController = storyBoard.instantiateControllerWithIdentifier("pauseWindowController") as! NSWindowController
pauseWindowController.showWindow(self)

Related

swift xcode iOS: can I re-use a loaded modal fullscreen view controller?

I have a storyboard with two view controllers. First one, VC_1, has one button that opens 2nd one - VC_2.
VC_2 also has a button that opens VC_1.
Both controllers have almost identical code:
class VC_1: UIViewController
{
override func viewDidLoad()
{
super.viewDidLoad()
print(“VC_1 loaded")
}
override func viewDidAppear(_ animated: Bool){ print(“VC_1 appeared") }
override func viewDidDisappear(_ animated: Bool){ print(“VC_1 disappeared") }
#IBAction func btnShowVC_2(_ sender: UIButton)
{
let storyboard = UIStoryboard(name: "Main", bundle: nil)
secondVC = storyboard.instantiateViewController(identifier: “VC_2”)
secondVC.modalPresentationStyle = .fullScreen
show(secondVC, sender: self)
}
}
The difference is only in "VC_2" instead of "VC_1" in the 2nd controller code.
I have seen this View Controller creation code in Apple documentation and many other examples around the Internet.
When I press the button on the VC_1, I see in the debug window, that VC_2 is loaded and appeared, and VC_1 is disappeared. And same, of course, happens when I press the button on VC_2 - it disappears, and VC_1 is loaded again.
My questions are:
what happens with View Controller object after "viewDidDisappear" has been called? Does it really disappear from memory, or "disappear" only means "you cannot see it on the screen?". I do not see "viewDidUnload" in the documentation...
I suppose that "viewDidLoad" means that new View Controller object was created in memory. Is there any way to load the View Controller object only once, and then hide and show it without causing "viewDidLoad" to be called? I tried to do it with global variable "secondVC" but got "Application tried to present modally an active controller" error.
viewDidDisappear: called after the view is removed from the windows’
view hierarchy. No, View controller object just left the view property. By the way the amount of memory used by view controllers is negligible. So dont think about too much. If you want to catch when Your View controller object release from the memory put
deinit { print("vc deallocated") }
viewDidUnload, it has been deprecated since the iOS
6, which used to do some final cleaning.
Partly true. Keep in mind ViewDidload called one time for the life cycle of view controller. There is a method called before viewdidload but this is not related with your question.
In addition to "There is a method before viewdidload" -> loadView( ) is a method managed by the viewController. The viewController calls it when its current view is nil. loadView( ) basically takes a view (that you create) and sets it to the viewController’s view (superview).

Launching ViewController as sheet from windowDidLoad

I'm trying to show a storyboard as a sheet right after the window has loaded.
override func windowDidLoad() {
super.windowDidLoad()
let storyboard = NSStoryboard(name: NSStoryboard.Name(rawValue: "Init"), bundle: nil)
let controller = storyboard.instantiateInitialController() as! NSViewController
self.window!.contentViewController?.presentViewControllerAsSheet(controller)
}
Unfortunately, the sheet is shown out of position and behind the window.
When I run the same code inside a button, everything works fine.
Screenshot
How do i correctly show a storyboard sheet after loading a window?
I have more knowledge of the iOS ecosystem but I suppose that you should show new windows only after the origin window has been shown. windowDidLoad is called when the view has been loaded, not when it has been shown.
Therefore, you should probably put your code into viewDidAppear of the contentViewController.

Opening window + view from an other view controller

I've got a ViewControllerOne. ViewControllerOne is connected via Ctrl-Drag (in storyboard) to a menu-button mBtn (which means I don't know how it is implemented programmatically).
Clicking on this mBtn, a ViewOne appears (present modal). This ViewOne is bound to ViewControllerOne. ViewOne has a button btnOne.
Clicking on btnOne I want ViewOne to be dismissed and ViewTwo to be shown. ViewTwo belongs to ViewControllerTwo and to WindowControllerTwo.
The WindowControllerTwo-ViewControllerTwo-binding is the standard case as created on a new project.
I have the following code in the IBAction for button btnOne in ViewControllerOne:
#IBAction func onbtnOnePressed(sender: AnyObject){
let m_WindowControllerTwo = NSStoryboard(name: NSStoryboard.Name(rawValue: "Main"), bundle: nil).instantiateController(withIdentifier: NSStoryboard.SceneIdentifier("WindowControllerTwo")) as! NSWindowController // I have no custom class for the window controller as I don't really know what I can use it for ...
let m_ViewTwo = WindowControllerTwo.contentViewController as! ViewControllerTwo // my custom class for ViewTwo
m_ViewTwo.attributeIWantToPassToThisView = self.x // an attribute I want to pass from view a to view b
m_WindowControllerTwo.contentViewController = m_ViewTwo // passing the attribute from a to b
m_WindowControllerTwo.showWindow(self) // this does not work
self.dismiss(nil) // see NOTE
}
This code actually does not work. On debugging it step by step, I'm seeing the window/view flickering but not appearing...
NOTE: I could connect the button btnOne with a ctrl-drag to ViewControllerTwo. This works. But then the current ViewOne does not get dismissed!
Question: What am I doing wrong here? In iOS swift this also works. I don't quite get the WindowController stuff, so I'll need your advice on this.
Instead of this: m_WindowControllerTwo.showWindow(self)
use:
let application = NSApplication.shared()
application.runModal(for: wordCountWindow) //this will present WindowControllerTwo modally.
then to close your present controller add this line: PresentWindowControllerName.close()

Instantiate View Controller not working

I'm trying to load another UIViewController so that I can get the data of the IBOutlets inside of it. I'm using Swift and Sprite-Kit. The UIViewController I am talking about is called GameViewController. It is the first thing that loads up in my game. Then it goes to my GameScene. This is where I am trying to instantiate my GameViewController. I want to do this because I am using a library called iCarousel and I want to animate it moving up from my GameScene. However, iCarousel can only be used on a UIViewController. So I want to call a function in GameViewController that will be called in GameScene. In this function, there is an NSLayoutConstraint that is used to move the carousel. Whenever I call this function, it says that its nil. Here is some of my code:
Inside my GameScene:
let storyboard: UIStoryboard = UIStoryboard.init(name: "Main", bundle: nil)
let firstViewController: GameViewController = storyboard.instantiateViewControllerWithIdentifier("Load-up") as! GameViewController
firstViewController.start()
Inside my GameViewController:
func start() {
// Constraint
top.constant = 100
UIView.animateWithDuration(2){
self.view.layoutIfNeeded()
}
}
If you need more information, feel free to ask me. Thanks in advance!
That is because your view controller hasn't loaded its view hierarchy yet. viewController loads its view hierarchy only when something sends it a view message. The system will do this by its own when to put the view hierarchy on the screen. And it happens after calls like prepareForSegue:sender: and viewWillAppear: , loadView(), self.view.
So here your outlets are still nil since it is not loaded yet.
Just try to force your VC to call self.view and then access the properties/outlets.
Edit: Added sample code.
let storyboard = UIStoryboard.init(name: "Main", bundle: nil)
let firstViewController = storyboard.instantiateViewControllerWithIdentifier("Load-up") as! GameViewController
debugPrint("Printing for the sake of initializing view of VC: \(firstViewController.view)")
firstViewController.start()

Present View from SKScene in Xcode 6 with Swift

I have a basic game running exclusively as SKScene. I would like to transition to a view called testview.xib but I cannot find any Swift examples of how to do so.
Here's my attempt based on other answers
let vc = UIViewController(nibName: "testview", bundle: nil) as UIViewController
self.view.window.rootViewController.presentViewController(vc, animated: true, completion: nil)
but the application fails with an error "Thread1: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode 0x0)"
The code for moving between SKScenes is
var transition:SKTransition = SKTransition.flipHorizontalWithDuration(1)
var scene:SKScene = otherScene(size: self.size)
self.view.presentScene(scene, transition: transition)
This turned out to be an issue with calling presentViewController() from within the init() method of the class. Basically, you can't call presentViewController() before the view/controller is setup; instead, you'll typically want to call it when some action occurs (button press, touch event, etc.).
The issue that was starting to be discussed in the comments and then moved in to chat was solved by loading the view controller from a storyboard instead of a xib. NOTE: An xib would work, but it's trickier to setup than a storyboard is.