Objective-C Reset NSView to Initial state from xib? - reset

I have an NSView with buttons and states that get altered during the course of the program. But is there a way to destroy that view and "respawn" the original one that was in the xib? I can hide and show NSView but what about destroying and recreating a specific view or restoring it to its initial state? Where every component on that view is "reset"? Is it possible to do this?

The way to do what you're asking is to have a separate XIB for the view. Its owner would be your view controller class (subclass of NSViewController). You would allocate an instance of that class and initialize it with the NIB name. When you first request its view property, that will load the NIB with a fresh instance of the view hierarchy. You would then replace the old view with the new view in the superview's subviews and, if you're using auto layout, set the constraints appropriately.
An easy way to add the view controller class and the view XIB in one step is to do File > New > File > Cocoa class. Set the "Subclass of" combo box to NSViewController. Enter the class name. Check "Also create XIB file for user interface". Click Create and where you want the files saved.
However, all of that said, the view should not hold state, it should reflect state. The model should hold state and the controller layer should configure the view to reflect the model, including updating it as the model is changed. So, if you've done things right, you should generally just reset your model state and that should reset your view.

Related

Connecting an NSTextField object to an IBOutlet in AppDelegate.swift

Recently, I've been trying to learn Swift, so if this seems to be a relatively simple question do forgive me.
For some reason, control-clicking a NSTextField object in a tab view controller and dragging doesn't give me the option to "insert outlet or action" but rather, "connect binding" when I scroll over a compatible object (in this case it was the superclass declaration).
Why is it that I am not able to insert an outlet or an action, but am able to connect a binding?
side question: what is a binding?
The outlet can only be a property of your nib file / storyboard scene's owner. Which is your view controller in most cases.
This is what happen what your view controller instantiated from storyboard:
Instantiates views using the information in your storyboard file.
Connects all outlets and actions.
Assigns the root view to the view controller’s view property.
Calls the view controller’s awakeFromNib method.
When this method is called, the view controller’s trait collection is empty and views may not be in their final positions.
Calls the view controller’s viewDidLoad method.
Use this method to add or remove views, modify layout constraints, and load data for your views.
Short Version:
UIKit instantiate your view controller for you, and add all subview as you required in storyboard. And connect(binding) subViews to their outlet (if you created one).
How to solve your problem
When you opened your assistant editor. Choose the automatic viewController, if that is not something your create, you should create a subclass of viewController you need (in this case, UITabViewController) and change your scene's class to that.
you need to have same view controller in storyboard when you control-drag a NSTextField to controller
Edit: As Leo mentioned in the comment You can't connect/create any IBOutlet in the AppDelegate file if you are using storyboard, you have to create in it's particular controller where you have placed NSTextField
Storyboard
As shown in the image if you are in storyboard click the top bar on the controller from there you will get the options shown in the image, select Automatic
If you have selected proper view controller in the storyboard it should show same viewcontroller file in the Automatic(viewController.swift) by selecting that file you should able to control-drag IBOutlet
XIB
In the Xib when you select Xib and click 'Asssistant Editor' it will generally take to the proper view controller if not select Automatic for it also as shown in the Storyboard image are that you will able to connect you IBOultet
Binding
When you control-drag IBOutlet it create a connection between your control and property of view controller
From Apple Doc
The Cocoa bindings feature enables you to establish a live connection between an item of data and its presentation in a view. Any change made to the data’s value, either in the view or in the object that stores the data, automatically propagates across the connection.
You can find more information regarding it in Apple Doc

Loading a custom UIView from a XIB file within a XIB for a ViewController view

I have an WizardSequenceViewController with an IBOutlet WizardView *_wizardView. In many WizardSequenceViewController.xib file I have the view outlet connected to the File's Owner - WizardSequenceViewController. I have a subview of that view defined with the class attribute set to WizardView. I have connected that WizardView to the outlet in the File's Owner. Finally, in my WizardView.xib I have a UILabel that I have placed in the file to test if the view is being rendered. When I select the WizardSequenceViewController from my tab bar, I see the superview view but not the subview _wizardView. When I set a breakpoint in my -(id)initWithCoder method in my WizardView.m file I see it stop there, so I know that it is calling that initializer (and thus it should be using the xib to load that file). I have tried many iterations and variations to get this thing to work but I can't and I am going crazy. Does anybody have any ideas?
From Apple doc "View Controller Basics, About Custom View Controllers":
The one-to-one correspondence between a view controller and the views in its view hierarchy is the key design consideration. You should not use multiple custom view controllers to manage different portions of the same view hierarchy. Similarly, you should not use a single custom view controller object to manage multiple screens worth of content.
Note: If you want to divide a view hierarchy into multiple subareas and manage each one separately, use generic controller objects (custom objects descending from NSObject) instead of view controller objects to manage each subarea. Then use a single view controller object to manage the generic controller objects.
Maybe you can't do a view-and-subview outlet setup in a view controller. And I'm not sure assigning the subview outlet to a separate NSObject subclass would work either, because how would you present it? Could you write your subview programmatically, using initWithFrame and addSubview, instead of making it an outlet? Or, if you really want to set it up graphically, could you assign it to a separate view controller as owner? Then the top view controller will call presentModal on the sub view controller. Or, if all you need is a UILabel as a subview, just add the label to the main view?
Even I faced a similar issue. But got it resolved by following steps given in the following link. Hope it helps.
http://blog.yangmeyer.de/blog/2012/07/09/an-update-on-nested-nib-loading

iPhone. View architecture

Can anyone summarize the relationship between the following items?
Content View
View Controller
Nib
the view, subclass of UIView
Application delegate
I got very confused about these. Coz some people say the "content view" contains the "nib" while other people say "content view" and "nib" are not containing each other.
Many thanks!
Oh man… that's not so easy. But I'll try.
Application is being launched from main().
Application delegate receives callbacks from Application during runloop. For example, when app finished launching or something else.
Usually application contains single instance of UIWindow, that is the root of all view hierarchy.
UIWindow can have UIViews, they can have UIViews by themselves. So, there's a hierarchy of UIViews (a tree)
Each view has controller, that gets user input and other events and controls UIView (for example, tells it to redraw itself because of user tap). Controller can be standard or custom, written by developer.
Content View is a normal view. Usually within a table cell. UITableViewCell instance has a property that is called contentView. It's a normal view and it can be any UIView subclass.
NIB is another story. You can create whole view hierarchy by yourself. But there is an alternative way: use Interface Builder. After creating views/subviews in the interface builder — you can save this hierarchy with all its properties as a single (serialized) file. And load it at once during application run.
NIB has three main objects. File Owner is an object, that you'll get when you send some message like
+ (BOOL)loadNibNamed:(NSString *)aNibName owner:(id)owner
Here owner will be filled with all properties of File Owner from the NIB.
First responder - first receives input. You can simply forget about it for now.
View — is the main view. Usually it is linked to a view property of File Owner.
It's a veeery short overview of all these things. You really have to read documentation to understand it better.

View or ViewController... both are views?

In Interface Builder... when I drag a VIEW into the document window... and then double-click on it... it opens and displays the VIEW window. (As expected)
... but when I drag a VIEW CONTROLLER into the document window... and then double-click on it... it also opens and displays the VIEW window, too. (It says "view" right on it.)
Is that right? (Or am I totally misunderstanding things?)
I thought a VIEW was the actual object to draw/drag things into. No?
I thought a VIEW CONTROLLER was just the CODE for your view. No?
I dont have experience with Interface Builder, but a a controller object provides the custom logic needed to bridge the application’s data to the views. In iPhone applications, a view controller is a specific type of controller object that you use to present and manage the views of your application.
Each ViewController has a View property associated to it, which is the one you are seeing in interface builder.
The view stored in this property represents the root view for the view controller’s view hierarchy. Whenever you present the view controller on screen (either modally or as part of view controller–based interface), this view is retrieved and displayed in the application window. The default value of this property is nil
Each view controller object is the sole owner of its view. You must not associate the same view object with multiple view controller objects.
Apple wants you to follow the Model-View-Controller system when you develop apps, and it's pretty straightforward and logical.
The Model is the core of your app. It processes databases, network connections and whatever you need. It's basically custom classes you create in Xcode.
The View is the interface between your app and your users. You can create them in Interface Builder and put them in NIB files (preferably one view every file).
The Controller is the glue between your view and your model. It defines the behavior and state of views (button enabled, label content, etc.) based on what it gets from the model (like a database). It also performs actions on the model based on the events it receives from the views it managers (controls), like changing records in a database or changing variables in objects.
The idea behind all this is that the model can be used in every platform with minimal modification.
Every controller should be linked to one view, and one view only, like a table (UITableViewController) or a screen's view (UIViewController). You subclass the controller you want and you add it to the NIB of the view it's associated with. That's how you do it:
In the NIB, select the File's Owner.
In the Identity inspector, set the class to the view controller you created in your project.
In your custom controller class, create IBOutlets for every view (such as deleteButton) in the associated view you need to have access to. Create and synthesize the properties for every outlet.
Create IBActions for every event you want to register (such as addButtonClicked).
In the NIB, drag a line with your secondary mouse button from the File's Owner to the wanted outlet view and then select which connection you want to make. Repeat until all your IBOutlets are properly connected.
Drag a line with your secondary mouse button from the view you want to register events from to the File's Owner and then select which connection you want to make. Repeat until all your IBActions are properly connected.
Write your code for the controller.

set view property in a UIViewController from a NIB programmatically (not during initialization)

At the beginning of my app, I am initializing a UIViewController with a NIB.
At some point, I am removing the view from the screen, then releasing it, so it no longer takes up memory. (At this point I am also saving the state of the view in the UIViewController)
At a later point, I want to recreate the view and bring it back on screen. I will then restore its state. (Using the same UIViewController, not a new one, since it saved the state)
My question, is when I recreate the view, how do I do so from the NIB, or is this not possible?
To me, the obvious remedies are:
Don't save state in the UIViewcontroller (Where does convention dictate that I do save state?)
Don't release the view (maybe just release all of its subviews?)
Don't load my view from a NIB, create programmatically (seems to go against using IB for everything)
Note:
I am not using a UINavigationController, I am handling the swapping of the views myself, since thee are only 2 of them.
If you need that level of control, you dont really want to use IB. Because, as you noted, if remove the view and then later recreate it, you would have to do it in code then anyway. Just design most of the views in IB, then write some code that generates just this view. Then you can call that same method again later to recreate that view when you need it.
You may be able to archive it and later turn it back into an object, but that seems like an inelgant solution. IB does not allow for dynamic creation of controls at runtime, even if they used to exist but don't anymore. There is no shame in leaving IB out of loop for this. In fact it's probably a good idea.
OR
If its a complicated view with a lot of pieces, put the view in it's own nib, and make a view controller for it. Then you can simply instatiate the view controller with the nib name, and add the controllers view as a subview to you main view. Then your view controller handles loading of the nib, and you get to design it in IB. Nothing says the view of a view controller has to take up the entire screen either.
self.otherController = [[OtherController alloc] initWithNibName:#"Other" bundle:nil];
[self.view addSubview:otherController.view];
Don't create the view controller and the view in the same nib file; either create the controller in code or put the view in a separate nib file. If you later nil out your controller's view property, the controller should recreate the view.
But why are you so worried about this? There's already a mechanism to automatically free up the view if you're low on memory: the low memory warning. It will only destroy and recreate the view if you actually need to do so, and it's built in to the system so you don't have to do anything. Remember the saying about premature optimization?