Loading Xib on UIView causing all the other components inside UIViewController hide - swift

Informations :
I am trying to swap two .xib which will be inside UIView of my StepsUIViewController class. And I set their file owner name as my StepsUIViewController because I want to do their procedures inside that view controller and that is the important thing at this topic.
Requirement :
My requirement is changing the two xib base on each situation. So,
since I set their file owner name as StepsUIViewController,
implementation of both xib will be done inside StepsUIViewController.
And I am going to present that StepsUIViewController modally. So there will be no UINavigationBar until I drag and drop from tools.
Here is my view hierachy :
And here is my StepsUIViewController :
So inside Step1View, I will change the two xib I created base on push(UIButton) action. Now here comes the problem. When I load those xib, UINavigationBar didn't appear as well as push button also disappear and instead that xib(UIView) cover the whole StepsUIViewController.
Here is my code :
import UIKit
class StepsViewController: UIViewController{
#IBOutlet weak var step1View : UIView!
override func loadView() {
super.loadView()
let someView = NSBundle.mainBundle().loadNibNamed("StepsInfo", owner: self, options:nil)[0]
step1View = someView as! UIView
}
}
Here what I am facing :
What am I doing wrong? I am new to xib and all my life dropping UIComponents to UIViewController inside storyboard and I am thinking to change it and create view dynamically on single UIViewController. Any Help?

Related

How to access storyboard items without #IBOutlets?

I am currently working in a IOS app where I have created a storyboard and some viewControllers.
Because many of the areas are similar I choose to create a generic viewController and then populate it with a controller that extends UIViewController.
Since I cannot add two different classes to a viewController in interface builder, I cannot link the viewController to two different controllers.
What would be the best way to accomplish such task?
Having a controller linked with the storyboard viewController and this controller handles every view that needs to be instantiated?
You can always use tags in Interface Builder for your controls.
For instance, let say you set a label with a tag of 100, and a button with a tag of 110.
var label : UILabel! { view.viewWithTag(100) as? UILabel }
var button : UIButton! { view.viewWithTag(110) as? UIButton }
So now, you can do things like:
label.text = "Yeppee!"

Setting SplitViewItem's ViewController

Im having trouble setting a nssplitviewcontroller's split view's view controller. I have a reference from the story board and am trying to set the items view controller programmatically:
override func viewDidLoad() {
dash = storyBoard.instantiateControllerWithIdentifier("dash_viewcontroller") as? NSViewController
print(dash)
main_view.viewController = dash!
}
I get this error from the console(doesn't crash) and doesn't show the programmatically set vc:
2016-02-21 10:03:19.475 HealthDash[62950:3960447] Failed to set (contentViewController) user defined inspected property on (NSWindow): Cannot remove a SplitViewItem's viewController if it is currently in a SplitViewController
Looks like the splitViewItem has a content controller that is actively being displayed. My guess: first you will have to remove that view controller from screen before you can replace it. Probably easier to create a new NSSplitItemView, add that to the NSSplitViewController and remove unwanted NSSplitItemView (and their associated view controllers).

How to change content view of Window?

I am developing an mac osx application which have initial window and viewcontroller launched from main storyboard. I want to replace the content view loaded by storyboard with my view.
I am doing this -
func replaceContentView() {
parentViewController = MainViewController(nibName: "MainContainerView", bundle: nil)!
let fullScreenFrame = NSScreen.mainScreen()?.visibleFrame
self.initialWindow.setFrame(fullScreenFrame!, display: false, animate: false)
self.initialWindow.contentView = parentViewController! . view
}
Problem with this approach is that the default viewcontroller is never getting deallocated. deinit() of default viewController is not called at all.
This is causing memory leak. So how to completely remove default content view and associated viewcontroller?
Storyboards don't deal in views, they deal in viewcontrollers. What a Storyboard does when it loads a view into a window is that it creates an NSViewController and then goes
windowController.contentViewController = theViewController
That implicitly also inserts theViewController.view as the window's content view. So do the same, and all will be fine.
Marek's example is wrong, because CustomView shouldn't be an NSView subclass, it should be a CustomViewController class that owns a view containing the label etc. As a bonus, NSViewController will take care of loading the XIB for you as well.
Alternately, you could set windowController.contentViewController = nil (which will remove the old view controller and its content view) and then set your content view. But really, why fight the framework when that's exactly what NSViewController is intended for?
You can write the code in deinit method,may it will help you.
deinit {
// perform the deinitialization
}
Your contentViewController within NSWindow instance still holds strongly its old view. You have replaced just property on your NSWindow instance.
To clarify what you have done:
NSWindow holds strongly against new view
NSViewController holds strongly against old view
You should assign your new view into contentViewController.view property as well
This might be helpfull:
NSWindow.h
/* NSViewController Support */
/* The main content view controller for the window. This provides the contentView of the window. Assigning this value will remove the existing contentView and will make the contentViewController.view the main contentView for the window. The default value is nil. The contentViewController only controls the contentView, and not the title of the window. The window title can easily be bound to the contentViewController with the following: [window bind:NSTitleBinding toObject:contentViewController withKeyPath:#"title" options:nil]. Setting the contentViewController will cause the window to resize based on the current size of the contentViewController. Autolayout should be used to restrict the size of the window. The value of the contentViewController is encoded in the NIB. Directly assigning a contentView will clear out the rootViewController.
*/
#availability(OSX, introduced=10.10)
var contentViewController: NSViewController?
/* The view controller for the window's contentView. Tracks the window property of the same name.
*/
#property (strong) NSViewController *contentViewController NS_AVAILABLE_MAC(10_10);
However what you do seems incorrect if you do this on launch.
You either set custom subclass of contentView to your new nsview subclass which can load it's view from another XIB (no need for storyboard).
Abstract example:
class CustomView: NSView {
#IBOutlet var contentView: NSView!
#IBOutlet weak var label: NSTextField!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
initSubviews()
}
override init(frame: CGRect) {
super.init(frame: frame)
initSubviews()
}
func initSubviews() {
let nib = NSNib(nibName: "CustomView", bundle: nil)
nib.instantiateWithOwner(self, topLevelObjects: nil)
contentView.frame = bounds
addSubview(contentView)
}
}
PS: topLevelObjects is set to nil because you hold strongly contentView. So no need to worry about memory management.

Adding NSNotification Observer using swift

I was using this example which explains the use of NSNotification.
In my case, I have a UIViewController in which I have a UITableView. To this tableview I am assigning a dataSource and delegate programatically by instatiating my UITableViewController. So far I have not declared any inits, and thus have been using the simple init() to initialize my UITableViewController. (This UITableViewController is not on the StoryBoard).
class foo: UIViewController{
#IBOutlet weak var fooTable: UITableView!
var fooTableViewController = MyTableViewController()
override func viewDidLoad(){
super.viewDidLoad()
fooTable.delegate = fooTableViewController
fooTable.dataSource = fooTableViewController
}
}
class MyTableViewController: UITableViewController {
override func viewDidLoad(){
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector: "notificationReceived", name: "TEST_NOTIFICATION", object: nil)
}
}
If I try to add the observer in viewDidLoad() of the UIViewController, it does not work.
So my question is: Does using the NSNotification require the usage of init(coder aDecoder: NSCoder)? If so, then what is the correct way to initialize using this init in swift? How should I be instantiating MyTableViewController in my UIViewController instance foo?
viewDidLoad is only called when the view of a view controller is loaded - in the code you're showing you create a table view controller subclass, assign it as the datasource and delegate of another table view (confusing, as it will already be the datasource and delegate of its own table view), but never actually do anything with the table view controller's view.
This means that viewDidLoad will not be called.
You should probably be adding your table view controller's tableView as a subview and also adding it as a child view controller so that rotation and appearance events are forwarded properly.
Note that the question and answer are nothing whatsoever to do with notification centers or Swift, but just about understanding the view controller lifecycle.
If you want a separate object to act as a datasource and delegate for your table view, great idea, but don't use a UITableViewController subclass. Just create a plain object which conforms to the data source and/or delegate protocols.

Changing label in other view in swift

I have a label in a second viewController in Swift, and I want change this between my firstViewController. I try this with prepareForSegue: also with ChildView and ParentView and accessing to label since parentView.. But I get error..
What is the correct form to can make this?
Try declared secondVIew:
class ViewController: UIViewController {
var v = View2Controller()
#IBAction func but(sender : AnyObject) {
v.label2.text = "newText" //Here get the error EXC_BAD_INSTRUCTION
}
...
class View2Controller: UIViewController {
#IBOutlet var label2 : UILabel
Thanks!
The more code you provide the easier it is to get answers.
In your case, you are initializing a band new View2Controller. Since label2 is an IBOutlet it expects data from a nib file. Since it didn't get any of this data, label2 is going to be nil hence why you get a EXC_BAD_INSTRUCTION crash.
You can access the root view controller of a navigation controller because navigation controllers are special in that they have their own stack and maintain their own view hierarchy. This is why you have to push and pop view controllers in a navigation controller. This also allows child controllers to maintain a reference to its parent controller.
The proper solution for your situation would be to use protocols. Otherwise give View2Controller a property and reference to ViewController then make changes to ViewController through that property.