Using Two Views with One UIViewcontroller - ios

I am using one simple UIViewController for my application which is not too complicated. It has two pages. On the first page I enter data in to text boxes to indicate user changeable data which will be handled on the second page.
#property (weak, nonatomic) IBOutlet UITextField *routeText;
When I am running my actions on the second page, I use a command like this to access what was typed in to the text box:
NSString *variable = [[NSString alloc]initWithFormat:#"%#",self.routeLabel.text];
self.consoleView.text = variable;
But the value is always (null). I am using the same TravelViewController.h/.m for all of the code. My question is: Is this not acceptable coding behavior to share it in this way or do I need to define the objects in a different way so the text can be shared between views?
Thanks for any help you could provide.

If it is a different view controller you need to pass the text from parent view controller to child using #property. Declare it in second class and when you are pushing from first screen to second, set this value in #property. After that you can use it in second screen using self.text.

Related

Is scoping the controller's code under a custom view a good cocoa design pattern?

As I was thinking about all the incarnations of MVC in Cocoa, I figured I could make a custom class for every View in the application and fill it with a datasource and delegate - stuff primarily considered for Controller.
This way, instead of having the infamous Massive-View-Controller, I could chop off pieces of code and put them in separate files - one class for one View - along with their datasource and delegates.
Is it a good idea, or what are the downsides?
I'm afraid that your idea sounds like you will end up with a bunch of bloated views instead of a bunch of bloated controllers.
What I'd suggest is to consider the Single Responsibility Principle: an entity should have exactly one purpose or function. What's a view's function?
It's a representation, in code, of a region of the screen. That means it needs to do two things: draw to its area and register interactions with the area. Anything that's not absolutely essential to those two subtasks shouldn't be in the view class.
This is the idea of the "dumb view". It has no logic, no decisions to make. It just gets handed some data to render. And when it gets a tap or a click, it doesn't know what the input represents, or try to figure out what to do about it. It just knows the type of the interaction and tells another object.
That other object is the view's controller. A view controller's responsibility is to mediate between the view and the rest of the system. It gives the view its data. It also accepts messages from the view about input, and then reconfigures the view based on the result of those messages.
The view controller doesn't necessarily need to compute the result on its own, however. That's usually where view controllers start getting into "massive" trouble. The view controller should pick another object to help it get the new values that the interaction produces.
One possibility for this other object is the view model, in the MVVM structure. The view model is a display-focused representation of the raw data for the view. It transforms the information in the model into whatever format the view needs, and re-transforms or updates the data in response to input from the view controller.
Another idea is to split that responsibility even more finely, using a VIPER arrangement. Here the formatting of the data is handled by a "Presenter", and the transformation of the data is the job of an "Interactor".
It's possible to get into architecture astronaut territory here; blindly applying a complex structure can bite you if a view's needs are inherently very simple. But even if you choose not to formally apply one of these alternative patterns, a view controller needs other objects. You will want "controllers" with other specific jobs, that get messages from the view controller and pass data back.
The important thing is to keep in mind the original idea I mentioned: strive to make each type do one thing and do it well. That will keep your classes focused; easy to read, understand, and think about; and testable.
View doesn't compute it's data, it just displays them. However if you have custom control it can have some logic to compute it's inner data to trigger value change inside model.
Your approach is an overkill with unnecessary code.
So you are facing a problem where you need to set some values of your custom NSView or custom NSControl (e.g. NSButton title).
Some of available MVC solutions:
set the value inside controller manually and call setNeedsDisplay method inside within view on the changed property.
set the model object as the property of view. However, this introduces tight coupling but still is ok (so the view has to
know/import model class). +Include update/refresh method within view
use bindings to nsobjectcontroller. You don't need to set Class of nsobjectcontroller (that is needed only if you need additional
functionality for it like creating object automatically on add
method).
MVC pattern reminder
View has target action mechanism which is triggered in controller. Controller updates model (nothing else!). Model then has to propagate that it has changed and controller should react to it. It shouldn't react in the target action.
With bindings you skip the target action but the latter remains
You can combine 2 and 3.
If you are beginner forget about VIPER pattern. MVVM can help you to reduce size of your controllers.
How to use binding with NSObjectController:
#import <Foundation/Foundation.h>
#import "AppDelegate.h"
#import "Value.h"
#interface AppDelegate ()
#property (weak) IBOutlet NSWindow *window;
#property (weak) IBOutlet NSObjectController *objectController;
#property (strong) Value *value;
#end
#implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
self.value = [[Value alloc] init];
self.objectController.content = [self value];
}
#end
#interface Value : NSObject
#property NSString *value1;
#property NSString *value2;
#property NSString *value3;
#end
#import "Value.h"
#implementation Value
- (instancetype)init
{
self = [super init];
if (self) {
[self setValue1:#"Value1"];
[self setValue2:#"Value2"];
[self setValue3:#"Value3"];
}
return self;
}
#end
There is also an option to unload View Controllers with Coordinator objects. Shortly: each task in the app is managed by a Coordinator object, which manages its View Controllers.
There is the main Coordinator object, that is retained by application delegate and that retains all other Controllers. All the logic that doesn't belong in View Controller, is moved up to the Coordinator.

Xcode - Retrieving value from textfield in different viewController

I have 2 viewControllers (NewTicket1Controller and NewTicket2Controller). View 1 has a text field named 'ticket' and view 2 wants to access that value.
Here is my code in View 2.
NewTicket1Controller *screen1 = [[NewTicket1Controller alloc] init];
NSLog(#"%#", screen1.ticket.text);
My NSLog statement above returns null for the ticket textfield value. But it's not null. If I switch back to view 1 I can see that there is a value in that field.
Can I not retrieve a variable like this?
When you instantiate a new NewTicket1Controller, all of it's properties are initialized to their default values. This does not give you a reference to any existing NewTicket1Controller objects. If you are using storyboards, you can pass it to the other view controller in prepareForSegue, or if you are not using storyboards, you can programatically pass it to the new view controller when it is created, assuming it is created from the NewTicket1Controller.
No need to initialize you view to access it. If you want to send text contained in textfield to another view..You need to store that ticket text field value into a string of other view controller..
At NewTicket2Controller take property with NSString with name ticketString and synthesize it...Then you can use that reference for storing value of ticket at NewTicket1Controller
At button action while switching to NewTicket2Controller..Put some code at NewTicket1Controller
NewTicket2Controller *screen2 = [[NewTicket2Controller alloc] initWithNibName:#"NewTicket2Controller" bundle:nil];
screen2.ticketString=self.ticket.text;//if you propertise the ticket textfield
NSLog(#"%#", screen2.ticketString);
Hope it helps you..
You just created and inited screen1. Any and all values will be nil or initialized.
A few things:
You want to try to keep the data (model) separate from your views and controller when possible.
You're going to have to provide some connection between the 2 view controllers.
One approach is to set up one as a weak link to the other.
Example for NewTicket2Controller
#property (nonatomic, weak) NewTicket1Controller *delegate;
And then when you create NewTicket2Controller you would assign self.delegate = screen1
After that you could access methods using the delegate.
(Ideally you'd setup a protocol for the delegate)
Others have given you partial answers. Let me state everything at once.
First, never try to manipulate another view controller's view objects directly. That is serious violation of the "encapsulation" principle of object oriented programming. You should treat a view controller's views as private, and add properties or methods to communicate between view controllers.
Second, you are creating a brand new instance of your view controller and expecting to be able to use that new view controller instance to alter settings in an existing view controller. This is like buying a new car that is a perfect match for your existing car, setting the radio station on that new car, and then wondering why the radio station on the old car doesn't change. They are different cars! They are different objects! They may be feature-for-feature identical, but they are different instances of the same object. If you had an identical twin, it is still a different person, right?
You need a way to get a pointer to your existing NewTicket1Controller object. How you do that depends on how your program is set up. Post some info on how you are setting up your view controllers. Are you using a navigation controller? Is NewTicket1Controller your root view controller? How are you getting from view controller 1 to view controller 2? A segue? (assuming you're using storyboards. Tell us if you're not.)

Connect two labels to one outlet

Now I understand that this question has been asked before, but the answers were unsatisfactory. My issue is that I have a view controller with a view and stuff in it including a label. I added a bunch of code for it and now I'm expanding on it. I now have an issue where I've decided to add another UIView to my interface and it has a label and that label is going to function EXACTLY like a label I have in my first UIView. My problem is that I don't want to have to go in my view controller method and add another line of code each time I manipulate that first label. Is there anyway I can link another label to my initial IBOutlet I have set for my first label? Or do I have to go in my code and add an extra line of code everytime I manipulate that first label?
It depends on what you want to do to that label. If you're looking to change some of the attributes of the label in the same way (e.g., font, text colour, alignment) then you can put both labels in an IBOutletCollection and iterate over the collection in your view controller.
If you want to have different data in the label, but other attributes the same, then you'll need a separate IBOutlet for that label.
You can combine the two techniques as well. e.g.
(interface)
#property (weak, nonatomic) IBOutlet UILabel *firstName;
#property (weak, nonatomic) IBOutlet UILabel *lastName;
#property (strong, nonatomic) IBOutletCollection(UILabel) NSArray *labels;
(implementation)
- (void)viewDidLoad {
[super viewDidLoad];
for (UILabel *aLabel in self.labels) {
// Set all label in the outlet collection to have center aligned text.
[aLabel setTextAlignment = NSTextAlignmentCenter;
}
[self.firstName setText:#"First Name"];
[self.lastName setText:#"Last Name"];
}
Basically the simple answer is no. Whether you use outlets or an outlet collection or tags or whatever, you ultimately have one reference in your code to one label in your interface, and another reference in your code to another reference in your interface. You can compress your mode of expression so as to cycle readily through those references (as suggested in a different answer), but the basic fact is inescapable that, ultimately, the only way to "talk to" a label is through the one reference that points to that label and to that label alone.
The only way of getting around that is not to use direct references at all. For example, a single message can be sent to multiple recipients by using an NSNotification. So you could have two instances of some UILabel subclass of your own, and "shout" to both instances simultaneously by posting a notification from your view controller - the notification is then automatically passed on to both labels, because you have arranged beforehand for them to register for it.
Similarly, another alternative is that you could use key-value observing so that a change in your view controller is automatically propagated to both labels automatically because they "observe" the change, meaning they are sent notifications - really just an inverted form of NSNotification. (If this were Mac OS X, you could make a simpler, safer version of this arrangement by using "bindings".)
However, I really cannot actually recommend that approach. The truth is that we still live in an excruciatingly primitive world of text-based programming, one line at a time, one command at a time, one reference at a time, and we must just bite the bullet and get on with it.
Swift 3, Xcode 8
Create a prototype cell with objects
then add another prototype
It will copy the objects from the first prototype cell.
The new objects will be connected to the same IBOutlet
Also, copy and pasting objects maintains IBActions, but does not maintain IBOutlets.
I hope this answers your question, as none of the other answers had this work around.

Changing value of an object from a different class

I have a ViewController.m with a UIButton and a UIWebView on it.
I've subclassed UIWebView to a class that is now called MyWebView.m.
What is the most efficient way to change the UIButton outlet location value from a method that is inside MyWebView.m
I thought about NSUserDefaults but it feels to me like it's the worst way to go.
Another thought was to copy the next line and also add it inside MyWebView.h:
#property (weak, nonatomic) IBOutlet UIButton *myButton;
and connect it to the button from ViewController.m but I'm also not sure if that's a right thing to do.
What does the button title represent, conceptually? Decide that, and expose it as a string property of your web view and then have your view controller observe the property with key value observing. Or alternatively, extend UIWebViewDelegate with your own protocol, and have the view controller set itself as the web view's delegate. Then have the web view notify its delegate that this value changed.
You can use the app delegate class for persisting the data through the application but this is also not recommended by the good programmers.
One other way is to use Singleton class . This creates only one object per application session so you can use the the value throughout the application also you can modify and access the value. This is the pure approach to go .You can take a look at http://www.galloway.me.uk/tutorials/singleton-classes/

Changing SearchDisplayController Delegate in interface builder

I'm trying to show a search bar above a table with a list of recent searches that will swap to matching search results once someone enters a search term.
I want to set a custom class MySearchViewController to be the delegate for doing the search and managing the display of search results back to the table so that I can separate the code and not have conditional statements in the default controller.
I've found a bunch of examples that describe how to do this in code but I can't figure out how to do it using Interface Builder.
I've tried dragging a new viewcontroller into my xib and setting the custom class to MySearchViewController and then dragging outlets from the SearchDisplayController as hinted at here: http://goo.gl/RgmwG
I've also tried dragging an Object into the objects column and changing this class to MySearchViewController.
But I feeling completely lost and really just trying things randomly. I'm guessing that I also need to create a property/IBOutlet for the SearchDisplayController somewhere but again lost.
If anyone has a reference to how to go about this I'd be so happy!
Like most problems, it seems pretty obvious in retrospect.
Add an 'object' placeholder in interface builder (orange cube).
Change the objects custom class to the class you want to be the delegate - e.g. MySearchViewController
Remove the default outlets from the standard SearchDisplayContoller to connect with the MySearchViewController object (see screenshot)
Make sure that the new delegate has an outlet to a parent view (in my case View)
Make sure that the delegate class is initiated from somewhere
// I did this from the parent ViewConroller, but probably better from the main app delegate?
#property (strong, nonatomic) IBOutlet MSSearchViewController *searchViewController;
Hope this helps someone else who was also stuck!

Resources