I have two view's in my app. In the first view I have a table view which displays data downloaded from the Internet. The FirstViewController has a method to get the data and update the view:
- (void)viewDidLoad
{
// Create PlanGenerator
_planGenerator = [[PlanGenerator alloc] init]
[self loadPlan];
- (void)loadPlan
{
_plan = [_planGenerator getData]
// Updating the view
// Updating the table view
[self.tableView reloadData]
}
To download the data from the internet I have a class called PlanGenerator. This class has an instance method called getData, it returns an NSArray. The table view uses the instance variable _plan (array) to display data in the table view.
In the second view (controlled by the SecondViewController) you can make some adjustments on what to download. To tell these change the PlanGenerator I used the concept of class properties. Now when I changed something in the second view (actually it's just one parameter) I want to call the method loadPlan from the FirstViewController.
My first thought was to create a class method, but then I would have to creat "class properties" for every variable the method uses.
Is there an easier way to do this?
You are missing some basics.
Try this design, assuming that FirstVC is used to display data and has tableview. SecondVC (your PlanGenerator) is used to get/download data.
In SecondVC:
Create whatever property(parameter, etc. says criteria) that FirstVC will supply to decide what to download.
Create a public method getData.
In FirstVC:
Create an iVar (says _myPlanGeneartor) and allocate it.
Now from the instance of FirstVC, you have access to an instance of SecondVC (_myPlanGenerator). With that you can supply criteria parameter and request data (getData).
Related
My app has a search view(search bar) which is used all over the app. I don't want to create duplicated code so I created a view controller called MySearchViewController to handle the search job, then I created a singleton object in AppDelegate. In every view controller, I added my search view like this:
- (void)viewDidLoad
{
MySearchViewController* search = [AppDelegate searchViewController];
[self.view addSubView:search.view];
}
My questions, Is it a good way? It's a singleton so it can be added to many views. Do I need to remove the view from last view before adding to current view?
Understand that you are mixing some concepts that are not necessarily related: avoid duplicated code and Singletons.
Wikipedia says this about singletons:
In software engineering, the singleton pattern is a design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical concept of a singleton.
The most important characteristic of a singleton (in my humble opinion) is that the object is instantiated only once and every single place in your application will use the same instance. Well, to use your search feature everywhere and avoid duplicated code you don't need the search view to be instantiated only once, maybe the data that comes with it, but not the view itself.
Two better ways of achieving this:
1 - You can create a ViewController with your search and just embed this on the other views using a Container View, you can use blocks or a delegate protocol to communicate between your controller and the view that is embedding it.
2 - You can create a Parent class of the ViewController that will include the search bar, like a SearchViewController and all the other viewControllers that needs the same feature will inherit from it.
The singleton could be useful if you are planing to share the same search data and text between all the ViewControllers of the application, but it would be a singleton only with these information, the UISearchBar and all other view elements should not be part of the singleton.
Ideally, you should instantiate a fresh instance of MySearchViewController every time when you want to add it to another view to avoid problems.
Do I need to remove the view from last view before adding to current view?
Its not required to remove it from previous super view because whenever you add this singleton MySearchViewController's view to some other view, it will automatically gets removed from last super view and now its super view is your new view where you have added it.
If you want to add a view from a different view controller, your view controller has to be that view controller's parent view controller:
- (void)viewDidLoad
{
MySearchViewController* search = [AppDelegate searchViewController];
[self addChildViewController:search];
[self.view addSubView:search.view];
}
also, make sure that when the search.view is added, it is already initialised.
Why you do not use NSObject class ?, i do not know your requirement , but if you want to store latest updated value in whole project(in execution) then you should use the singleton, but if you do not want to store value (i mean one result for whole project) then you should use NSObject derived Class. advantage is singleton consumes memory so memory will be wasted. NSObject class will be reusable and only allocated when it is required and then ARC will take care of all things. If you want to know how to create NSObject and use of it then you can give me reply.
Here is some code to load a XIB as part of a custom object with the object gets initialized.
Why are you not creating custom search component for search?
you can use this component all over the app.
also this is not creating duplicat code.
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code
[[[NSBundle mainBundle] loadNibNamed:#"SearchView" owner:self options:nil] objectAtIndex:0];
[self addSubview:self.view];
self.frame = self.view.frame;
}
return self;
}
Please check below code. Hope this is work for you.
- (void)viewDidLoad
{
if ([self.view viewWithTag:123456]) {
[[self.view viewWithTag:123456] removeFromSuperview];
}
MySearchViewController* search = [AppDelegate searchViewController];
search.view.tag = 123456; // give a any random tag to view
[self.view addSubView:search.view];
[self addChildViewController:search];
}
Please make sure given tag is not assign to other object except search.view in self.view.
Thanks
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.)
I have about 8 view controllers in my app, and i have a function in each one that does the exact same thing. I was hoping to be able to condense it into one central function that can perform the task for all 8. The function would need to receive an instance of itself so that it could perform the task on the appropriate view controller, but since i have no idea which one is being passed i set the instance type as UIViewController *. That way, i'd be able to receive any of the view controllers. The problem is i have to execute a method from this method, and since each method is custom to those child classes to UIViewController and im PASSING UIViewController, i can't access the functions from the instance. Is there some way to do this? Access a child class method from an instance of the parent class? Here's some code:
- (void)changeIsFullscreen:(UIViewController *)viewController { // <-- Right here is the
// ^^^ instance of the class that's passed to the function. I
// can't pass the child because there are so many different
// children that will be using it.
if (isFullscreen == NO) {
[viewController setIsFullscreen:YES]; // Right here is the child
// class method that i need to call.
// They all have the method, and if they
// don't i could use try/catch blocks to
// catch the error if there was some way to do it.
} else {
[viewController setIsFullscreen:NO]; // Right here is the child
// class method that i need to call
}
}
I know one way to do this would be to extend UIViewController, create the method in THAT class, and extend all the other child view controllers from the new class i just extended. I don't know if that is the correct way to accomplish this task, though. Is it? Or should I do it another way?
I may be missing something obvious here, but if all of your view controller subclasses implement this method, it sounds like they should all derive from some intermediate class. So, you'd have a class that derives from UIViewController and implements -changeIsFiullscreen, and all of your view controllers are derived from that class.
I have a scenario where there is a parent container view controller with a subview taking up most of the screen. This subview is used to swap out 3 different views of the same data (a map, a table and a gallery). There is a segmented control that is used to select which view of the data the user wants to view. I have an array collection of my model type in the parent container view controller and I would like to have these 3 different child view controllers each display this data in their respective views. Is there any clean way to do this without having to duplicate the data 4 times (once in the parent and 3x in the children)? I'm assuming I will have to duplicate the data, because the child should not be able to call up to the parent view controller to access its array. It's also not an appropriate inheritance situation, since the parent is more of a container than the same type of view controller. It's also not a delegate situation, because the children don't need to notify the parent of anything, but the other way around.
Any suggestions greatly appreciated.
Thanks.
I would create a class (MyDataController below) to manage the data, and use a shared instance to access it from anywhere in my app.
interface (MyDataController.h)
#interface MyDataController : NSObject {
NSMutableArray *myData; // this would be the collection that you need to share
}
+ (MyDataController*)sharedDataController;
// ... add functions here to read / write your data
#end
implementation (MyDataController.m)
static MyDataController* sharedDataController; // this will be unique and contain your data
#implementation MyDataController
+ (MyDataController*)sharedDataController
{
if (!sharedDataController)
sharedDataController = [[[MyDataController alloc] init] autorelease]; // no autorelease if ARC
return sharedDataController;
}
// ... implement your functions to read/write data
#end
Finally, to access this static object from anywhere:
MyDataController *dataController = [MyDataController sharedDataController]; // this will create or return the existing controller;
You could put the data in a singleton class and just have each of your child view controllers get the data from the singleton.
My question relates to Assignment 3 in CS193p.
Im having a terrible time getting drawRect in my View to receive information passed from my View Controller. Basically, my goal is to pass view-specific information (like self.view.size.width) to the controller, have it make some modifications (like result = self.view.size.width * 2), and pass result back to drawRect so that it could take the new info and draw it. Im pretty sure I have my delegation set up correctly, and really have tried a list of potential work-arounds:
make a public View #property, which I access in my controller.m via
View *newView
someResult = newView.variable
which I would then try to access from my view.m via
self.variable
use methods set in my View's #protocal, which I try to pass data via myView.dataSource someMethod:someData
But so far none of these are currently working (i.e. my self.variable would always come out to be 0, which shows that no data was passed to it). Your help much appreciated!
UPDATE:
The culprit was that, in the storyboard, I didn't control-drag the View Controller to the View, and hence the Controller was never connected... but at least now it works. ^_^
View *newView someResult = newView.variable is not valid syntax.
If newView.variable is not of type View then that is a problem.
If newView is already declared, you would access variable using int myValue = newView.variable (that is, asuming it is of int type).
An example would be:
// Somewhere in your code, you declare your object
UIView *otherView = [[UIView alloc] init];
// Somewhere else, you set a variable of your object
otherView.backgroundColor = [UIColor blackColor];
// Again, somewhere else you want to access that value
UIColor *thatColor = otherView.backgroundColor;
I hope this explains it well enough.
Is this the correct description of what you want to do? You have a view controller (presumably the calculator type view controller from the course) and you want to communicate between that view controller (whose view has the calculator buttons) and a view other than it's own?
If so, here are the steps you should take:
In your view that you want to receive information from a delegate:
Declare an #protocol with the method you want the delegate to implement. Declare a property in the header file of the view that conforms to the aforementioned delegate: #property (nonatomic, weak) delegate<NameOfTheProtocol> delegate;
In the view controller you want to act as the delegate, declare it conforms to the protocol: MyClass: UIViewController <NameOfTheProtocol>. In the implementation file of that view controller, implement the methods of the protocol. Where ever you create the view that you want to receive information, set it's delegate property to your view controller.
To pass information between them (I have no idea what information you want to pass), your protocol method might be something like: -(CGPoint)pointToDrawAtGivenPosition:(CGPoint)point
In your view that has the delegate property, you could in drawRect do something like:
CGPoint pointToDrawAt = [self.delegate pointToDrawAtGivenPosition:CGPointMake(100, 100)];
//Now draw that point or whatever.
Basically, the view is asking its delegate to make a decision about where to draw something. It passes some information to the delegate, and the delegate responds with the correct position for the view to draw at.