Please note this is not an iOS question.
I have an NSView-based app (i.e. not document-based), and I’d like to bolt on a printing subsystem. I can get NSViews in my main controller to print ok. However, I want to have a special view constructed just for printing. The view should not show in the app’s window. The view contains two NSTextFields, two NSTextViews, and 5 labels.
I cannot seem to figure out a way to do this. I have tried various forms of these examples:
Add an NSView to my main view window? Seems logical, but it’s awkward in a storyboard, (I can’t position the view in the storyboard).
Programmatically create a custom NSView with a xib?
For this, I’ve tried:
#IBOutlet weak var printView: NSView!
….
let printOperation = NSPrintOperation(view: printView!)
This results in the comprehensive "fatal error: unexpectedly found nil while unwrapping an Optional value” message.
The outlets are configured correctly (I think)
A seperate ViewController? If so, how can I avoid having two print buttons — one to call the print controller, and the second, to print the PrintController’s view.
I’ve tried reading the Apple docs, but they are not the way I learn best. There are also no Print documents in Swift that I've found. I’ve waded through many SE questions, but have come up blank. Could you point me towards a solution please.
I think the specific problem here is that you're never causing the view to be loaded.
You can double check whether this is the case by overriding the viewDidLoad method on the controller. If it's never called, your view is never loaded from the nib.
Normally the UI machinery takes care of all that when you display a view controller, which is why it can be so confusing when it doesn't happen.
You should be able to trigger the view load by accessing the view property on the controller. e.g.
_ = self.view // Touch the view to force it to load
https://developer.apple.com/documentation/appkit/nsviewcontroller/1434401-view has some additional information.
You can also call loadView() directly although that's usually frowned upon.
Imagine an app that shows a list of questions, each question has a type associated with a particular UIViewController (so there are several UIViewController objects for each type of question that the app supports). Users cannot go back to previously answered questions. I would like to show each controller with the same effect given by the pushViewController method.
Here's the catch. There might be a very big number of questions presented by the app, so keeping all those UIViewController objects in memory is not a viable option. Because there is no option to go back to a previously answered question, the app only needs to keep track of the last two questions displayed (for animation purposes, when the current question is shown above the previous one).
Any suggestions of how I can implement this in Swift? (I am also fine with an ObjectiveC solution if I can later convert it into Swift).
Subclass a UINavigationController then set the delegate of the navigation controller to itself and then when a controller is shown, remove all other controllers from stacks except the one that is showing. That way, your navigation controller will have only one view controller at any time and you will not be able to pop but only push the view controllers.
Here is a small sample,
class MyNavigationController: UINavigationController, UINavigationControllerDelegate {
// MARK: UINavigationControllerDelegate
func navigationController(navigationController: UINavigationController, didShowViewController viewController: UIViewController, animated: Bool) {
self.viewControllers = [viewController]
}
}
Then, push all your viewcontrollers inside this view controller. And that should do it.
I have the following question:
Is it possible to ask the StoryBoard to load a viewController without displayed it?
My problem is the following:
I have two viewController "Diaporamas" and "Settings". "Diaporamas" needs to know the state of a switch "With Frame:" from the viewController "Settings", but "Settings" is not loaded, because the customer has not selected them for the moment!
My tests:
I try this couple of calls:
hc_Settings_Class = [self.storyboard instantiateViewControllerWithIdentifier:#"SettingsViewController"];
// these line to force storyboard to load all controls in the "Settings" viewcontroller.
hc_Parameters_Class.view.hidden = NO;
[hc_AppDelegate_iPad loadPreferences];
the storyboard loads the right viewcontroller "Settings" but of course with an instance address different from the one instance loaded when the user selects them with the user interface. And of course, the "Diaporamas" viewcontroller doesn't know the real stat of all controls in the "Settings" viewcontroller!
Hope my question was clear enough.
I had an answer from another forum and effectively, I will using "NSUserDefaults" and use its feature that consist to function as a "singleton"! I was using a heavy mechanism which implemented global variables ...
Why make it complicated when it can be easier!
I'll clean my code and have a better use of NSUserDefaults!
Thank you to everyone who took the time to read my question. ;-)
Well, "not getting it" is too harsh; I've got it working in for what for me is a logical setup, but it does not seem to be what iOS deems logical. So I'm not getting something.
Suppose I've got an app that shows two pieces of information; a date and a table. According to the MVC approach I've got three MVC at work here, one for the date, one for the table and one that takes both these MCVs and makes it into a screen, wiring them up.
The master MVC knows how/where it wants to layout the two sub MVC's. Each detail MVC only takes care of its own childeren within the bounds that were specified by the master MVC. Something like:
- (void)loadView {
MVC* mvc1 = [[MVC1 alloc] initwithFrame:...]
[self.view addSubview:mvc1.view];
MVC* mvc2 = [[MVC2 alloc] initwithFrame:...]
[self.view addSubview:mvc2.view];
}
If the above is logical (which is it for me) then I would expect any MVC class to have a constructor "initWithFrame". But an MVC does not, only view have this.
Why?
How would one correctly layout nested MVCs? (Naturally I do not have just these two, but the detail MVCs have sub MVCs again.)
Thanks all for replying. I will study the links that were provided.
Let me try to explain my issue one more time, hopefully to making it more clear. Do note that I already figured out that my view does not match iOS's, since I do not like where my code is going.
Yes, I'm calling a UIViewController an "MVC", since it for me at the moment implements all aspects of a MVC; it has controller code and an embedded view, plus the controller usually also holds and provides the data (all TableView examples implement it like this).
MVC can be present on many levels; basically a UITextField could (should?) be a MVC; there is a view, but also controller logic involved that you do not want to mix with other code. Encapsulation. For example: Java's Swing JTextField has a MVC. So does a JTable, JList, ... Multiple MVC patterns nested in other MVC's to build a whole screen.
This what I expect when some platform says it uses the MVC pattern. So When I coded the table, I created a MVC and only send the loadData message with a date as the parameter to it. It needs to take care of the rest itself. I have a Detail MVC that can slide in; I then tell it the object it needs to show and it needs to take care of the rest itself. Encapsulation.
So I have a lot of UIViewControllers with embedded UIViews. And that is not the way to do it...
One more potential link is the great talk from WWDC 2010 on MVC.
http://developer.apple.com/videos/wwdc/2010/
It is Session 116 - Model-View-Controllr for iPhone OS
The session is chock full of practical advice on how MVC really works, what makes it tick, why it's good. But it also has a lot of intro stuff to help folks new to the concept to wrap their heads around it.
If I understand your sentence on Java's Swing classes above are you talking about the anonymous classes that respond to events? If so those are not "MVC's", they are what is termed 'Observers', when they observe an event from the view they take some action (usually send a message to a controller). Cocoa Touch uses the Target/Action paradigm (and delegation) to achieve this.
I'd also strongly suggest you take Matthew and Stephen's advice and write a bunch of code. If you don't build that base of intuition, asking the right question (which is most of what is needed to get a good answer) is very difficult.
I really think the WWDC 2010 talk will help.
Good Luck!
If I understand your question -- and I may not, see my comments on it -- I think you're applying the MVC design pattern far too granularly. Most commonly in the setup you describe you'll have a single Model, a single Controller, and multiple Views that are grouped/combined, as in a .xib file.
In Cocoa Touch terms you'd have one UIView that contains a UILabel with the date and a UITableView for your table. These are your Views.
You'll certainly have a Model for the table data, likely an array of data. Your date data might be from its own model if it's a date retrieved from something or calculated or whatever, something entirely separate from the array of data. If it's instead associated with the array data -- they're both pulling from a database, or the date is calculated from the array data, or what have you -- then you have a single Model.
If the data is all coming from a single Model then a single Controller is likely fine. Even if the data is coming from more than one source/Model you likely only need/want one controller in this setup. The UITableView will have a UITableViewController, and that same controller can take care of providing your date as well.
To sum, the Model View Controller design pattern doesn't call for having a bunch of nested sets of models, views, and controllers. They could be, and sufficiently complex projects may call for it. Broadly, though, you'll have a controller that's associated with a model and one or more views, and that set of objects works together to provide a piece of functionality.
Tbee,
I'll post a tiny code example here, since it seems you're not really getting it.
#interface MyView : UIView
#property (retain) IBOutlet UIButton *button1;
#property (retain) IBOutlet UIButton *button2;
#property (assign) bool myData;
-(IBAction) doButton1:(id)sender;
-(IBAction) doButton2:(id)sender;
#end;
#implementation MyView
#synthesize button1 = _button1;
#synthesize button2 = _button2;
#synthesize myData = _myData;
// I'm leaving out the initWithNib, viewDidLoad, etc.
- (IBAction) doButton1:(id)sender
{
// do something as a result of clicking button1
_myData = YES;
}
- (IBAction) doButton2:(id)sender
{
// do something as a result of clicking button2
_myData = NO;
}
#end
Connect those up in InterfaceBuilder, and you've got a working "MVC." You don't need a completely new UIViewController for each button. The one for the View takes care of it.
UITableView and it's associated Views are more complex, and may require an additional UIViewController to help encapsulate. I really don't suggest starting out by using them, but this is a good tutorial here. It's got a lot of images which will show you how to connect things up in IB and the like. It's old, so your XCode may not look like the images, but it helps.
Thanks for the links, I'll look into them.
So far I've rewritten most of my application to using views instead of viewcontrollers (except the toplevel one) and it starts to match up with the API calls that are available like layoutSubviews. What I find disturbing that I need to do this now:
[tableDataSource loadData:date];
[tableView reloadData];
Where in my previous setup all I did was:
[tableViewController loadData:date];
But apparently that is the way to do it. One thing is unclear to me ATM. Since I construct and layout the view in loadView in my AppViewController, how do they get relayouted if the orientation changes. The VC does not have a layoutSubviews, so I should use the didRotateFromInterfaceOrientation and reposition the subviews from there?
BTW, I'm not mixing registering anonymous inner classes as listeners (observers). I'm very experienced with writing Swing components and JavaFX controls. And that probably is the culprit, in Java(FX) every component has a view and a controller (not always a model).
I am reading many posts about UIViewController managing but I can't find the solution to my problem. I am making an iPhone game. I have three screens (menu, game play and scores) constructed into the Interface Builder and from three UIViewController classes. Into the main menu I have two custom buttons that allow to go to the game play screen or to the scores screen. Actually I am using the next method to navigate but when I use it, even it changes the screen and takes me to the game play, I can't see the highlighted state of the custom button. Must I change the views like this? How can I show the custom state of my buttons? How can I show an animation while the views are changing?
- (IBAction)gotoPlayViewController:(id)sender {
//Navigation logic may go here.
PlayViewController *playViewController = [[PlayViewController alloc] initWithNibName:#"PlayViewController" bundle:nil];
self.view = playViewController.view;
[playViewController release];
}
Thanks for readding.
You want to use UINavigationController, don't you?
The UINavigationController class implements a specialized view controller that manages the navigation of hierarchical content. This class is not intended for subclassing. Instead, you use instances of it as-is in situations where you want your application’s user interface to reflect the hierarchical nature of your content. This navigation interface makes it possible to present your data efficiently and also makes it easier for the user to navigate that content.
Here is a nice tutorial.
Here is the class reference.
UINavigationController also provides a very easy way to add the slide transition you want.
Have fun!