I have 3 view controllers.
Navigation Controller - N
Table View Controller - T
Custom View Controller - C
Their layout is like so:
N -(root view controller)-> T -(bar button item Add - Triggered Segue)-> C
Just to clarify, T has an "Add" button which has a triggered segue action to present C modally.
C and T both have custom classes. C is a simple UIViewController subclass while T is a UITableViewController subclass.
In T I declare an NSMutableArray and a UITableView like so:
#interface T: UITableViewController {
NSMutableArray *myTableData;
IBOutlet UITableView *myTableView;
}
In C I have two elements within:
A UITextField
A UIButton called "send"
I connect the text field to an IBOutlet like so in C's header, as well as create an action for the button:
#interface C: UITableViewController {
IBOutlet UITextField *itemToAdd;
}
-(IBAction)addItem:(id)sender;
So I have the data array myTableData which populates T's table declared and initialized in T (I will add a myTableData = [[NSMutableArray alloc] init] in the viewDidLoad method of T.
When the "add" button in the navigation bar of T is clicked it will obviously bring up C and take in some text from the text field.
Then finally when the send button is pressed I want to add that text from the text field into the myTableData array, dismiss C (which I plan on doing with [self dismissViewControllerAnimated:YES completion:nil], and update the table view myTableView to reflect the changes that I have made.
Does anyone have any idea on how I could accomplish this? Mainly I need help somehow accessing myTableData (that lives in T) FROM C. Then I need to get T to recognize that some change has been made and to redraw its cells (probably by instigating cellForRowAtIndexPath). I am aware of how to do this all hardcoded Apple's docs, but I find that method isn't viable if you want to visually represent everything in the storyboard and they do not explain what everything means exactly (like itemInputController for instance).
If my approach is totally incorrect and I don't need all these classes or methods or am doing it all wrong, please feel free to give me a similar approach using the storyboard.
Create an NSMutableArray and store it in your NSUserDefaults. Here's how:
In your C - UIViewController, on the send button IBAction :
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSMutableArray *arr = [defaults objectForKey:#"data"];
[arr addObject:WHATEVER_YOU_WANT_TO_ADD];
[defaults setObject:arr forKey:#"data"];
[defaults synchronise];
You can use this same method in T!
Related
I have two View Controllers: SavePopOverVC and MainVC. I also have a nib file called SavePopOver. SavePopOver has three items, a UIButton, a UIImage and a UITextView. The image and text view have outlets to property fields in SavePopOverVC called captionImage and captionTextView respectively. The button has an outlet to an IBAction in SavePopOverVC.
In MainVC.m I have the following two lines in my class extension.
SavePopOverVC *spvc;
UIPopoverController *popover;
In my viewDidLoad of the same file I have the following lines relating to my popover.
spvc = [[SavePopOverVC alloc] initWithNibNamed:#"SavePopOver" bundle:nil];
popover = [[UIPopoverController alloc] initWithContentViewController:spvc];
In my function that displays my popover, also in MainVC.m, I have the following lines.
[popover setPopoverContentSize:CGSizeMake(600,200)];
[popover presentPopoverFromRect:_header.frame inView:self.view permittedArrowDirection:UIPopoverArrowDirectionAny animated:YES];
[((SavePopOverVC *)popover.contentViewController).captionTextView setText:#"Some text here"];
However, captionTextView is nil when I make the setText: call. The app doesn't crash but the text isn't set. After the popover is displayed and I click on the UIButton to save the string typed in captionTextView I get the string just fine. So, I know the two are ultimately linked correctly, but how can I set captionTextView from when I display the popover?
If it is worth noting, I'm developing solely for iPad with this one.
It is most likely nil because its view isn't loaded at the time you set the text. Unlike most other modern languages, in Objective-C calling a method on a nil object doesn't cause an exception, it just does nothing.
To solve this, you can create a custom NSString property in your SavePopOverVC, e.g.
#property (nonatomic, copy) NSString *caption;
Before you call presentPopoverFromRect:, assign a value to this property. Inside SavePopOverVC, override viewDidLoad and set the captionTextView.text = self.caption;
There might be people who disagree with me, but I don't recommend exposing UI controls as properties in a view controller. This behaviour is one of the reasons for that.
I am trying to learn iOS development but have stalled a bit so I hope that there is some kind soul here who might be able to help me in the right direction.
Let's say I have a UITableViewController that displays a number of items, consisting of a title and subtitle ( Subtitle style of a Tableview Cell). Items.m/h only consist of two properties, title and subtitle and a init method to set the properties. In my app delegate i create some default items and pass them/set them to my tableViewController's property tvc.items, which is a NSMutableArray. What do I need to do / what components do I need, to be able to add more items and then display them in my tableViewController?
I started with the following:
Added a new view controller in the storyboard
Embeddade the viewController in a Navigation Controller
Added a Bar Button Item at my Table View Controller with an identifier of add
Ctrl + drag from BarButtonItem (add) to my new view controller selected modal segue
Created a new class AddNewItemViewController
Entered this as the class under the Identity Inspector for the new view controller
I then added two Bar Button Items, Cancel and Done (with cancel and done as identifiers) in the storyboard for the new View Controller
This was followed by me adding two UITextFields, one for the Title and one for the Subtitle
Ctrl + drag from these outlets into AddNewItemViewController.m, between #interface AddNewItemViewController () ... here ...#end (so they become Private? Should I drag it here or to AddNewItemViewController.h ?, What is the standard way for doing similar outlets?).
In AddNewItemViewController I added two properties, NSString's (nonatomic, copy) * title and *subtitle which I thought would keep the input data from an intended user.
So, after this I now want do two things, and it is here as it becomes difficult (for me at least):
Making so that by clicking on Cancel, one return to the Table View controller, ie a dismissed the modal .
Adding the data within the text fields to that NSMutableArray which is the datasource by clicking Done.
So what is required of me to do the last two steps?
Where should I ctrl + drag from the Cancel and Done (so there will be actions)? I guess they must be submitted to AddNewItemViewController.m, but what must be done to dismiss the modal (by clicking on the 'Cancel') and what should be called at or performed when clicking on 'Done'?
Which or what class (es) must know about the other class?
Last but not least, what should I send in the prepareForSegue call (which I guess I will need to have to use to send the input data back to the table view controller)?
Where to start and what methods should i learn about in order to achieve my mission?
Best Regards,
Rookie
much quesetions :)
I will beginn with the close action.
Have a look at the AppleDocumentation, dismissViewController with sender self (your AddViewController).
To store your data from AddViewController to your TableViewController, it's a better way to use delegation.
AddViewController.h
#protocol AddViewControllerDelegate;
#interface AddViewController : UIViewController
#property (nonatomic, weak) id<AddViewControllerDelegate>delegate;
#end
#protocol AddViewControllerDelegate <NSObject>
- (void) addViewControllerDidFinishTakingData:(AddViewController *)addViewController withTitle:(NSString *)title andSubtitle:(NSString *)subTitle;
#end
AddViewController.m
- (IBAction)done:(id)sender
{
NSString *title = ...;
NSString *subtitle = .. .;
[self.delegate addViewControllerDidFinishTakingData:self withTitle:title andSubtitle:subtitle];
}
TableViewController.m
#interface TableViewController ()<AddViewControllerDelegate>
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"yourIdentifier"])
{
AddViewController *addViewController = (AddViewController *)segue.destinationViewController;
addViewController.delegate = self;
}
}
Last but not least to implement your new delegate-method
- (void)addViewControllerDidFinishTakingData:(AddViewController *)addViewController withTitle:(NSString *)title andSubtitle:(NSString *)subTitle
{
// handle your data here (store to array)
// reload your table
}
Better way, to create a Class (Model) for every entry.
The simplest thing to do would be to assign tvc.items to the destinationViewController's property during prepareForSegue.
You are correct in thinking that the Cancel and Done buttons belong to the AddNewItemViewController.
In the action for Done, you could add the new item to the items array you passed in during prepareForSegue, then in the presenting view controller (the one you launched the modal from), during viewDidAppear just reload the table. It'll be called when the modal disappears.
I need to know how to keep the data they contain elements of View (TextField, etc) after pressing a button that leads to another view and then return to the initial data keeping at first sight establish a price in the second defined as that price should we pay each guest, to return to the view in which the price is set, data proviamente introduced, and the total has gone ... (I try to return an array of diners).
ContactosViewController.h
#class ContactosViewController;
#protocol ContactosViewControllerDelegate
- (void)addItemViewController:(ContactosViewController *)controller didFinishEnteringItem:(NSMutableArray *)item;
#end
#property (weak, nonatomic) id <ContactosViewControllerDelegate> delegate;
AltaViewController.h
#interface AltaViewController : UIViewController <ContactosViewControllerDelegate>
AltaViewController.m
-(void)addItemViewController:(ContactosViewController *)controller didFinishEnteringItem:(NSMutableArray *)item
{
NSString *personaString =[NSString stringWithFormat:[item objectAtIndex:0]];
self.altaResumen.text=personaString;
[self dismissViewControllerAnimated:YES completion:nil];
}
I'm new to this taking references from various places, I appreciate any contribution however small.Thank you very much.
Your question is VERY hard to understand. I have the impression you have the following problem:
You have a view controller, probably set up in storyboard, that contains some interface elements (UITextField, etc.). The user enters something there, before he/she is shown another view controller, whose view is used to enter additional data (price, etc.). When you return from the 2nd view, you want to have the data entered in the 1st view still available.
If this is the case, you simply had to define properties of the 1st view controller, and assign the data entered to them. If the data is e.g. a NSString, you probably would use something like
#property (nonatomic, strong) NSString *myString;
Declaring them as strong (default) will keep the data alive at least until the view controller is itself deallocated.
I have a first UIViewController where data is entered into a textField, a button that when clicked leads to another view where additional data are allocated and once introduced back to the initial view, the back, the view has lost the data entered above.
I have a UIViewController class and a UITableViewController class. Within the UIViewController class I have an NSMutableArray.
I now have the issue of how to load data into my table view, a separate class, I must access the NSMutableArray I used to populate the previous UIViewController class.
I tried using a delegate to access the array in the UIViewControllerClass however the array had "0 objects" and was NULL
I would appreciate some guidance in the right direction here.
You could have one view controller hold a reference to the other view controller and query the public NSMutableArray on it for data. Aaron suggested this and it might be your best solution.
Or.. you have multiple view controllers trying to access the same set of data. Potentially you have other classes which will want to access this data also. You might want to consider pulling the data out of the view controller and storying it in a neutral location. You could store it in the AppDelegate and then reference the app delegates from any place you need it.
id<UIApplicationDelegate> appDelegate = [UIApplication sharedApplication].delegate;
NSMutableArray *myData = appDelegate.data;
You could also consider pulling all the logic of your data and the data itself into a separate class and use a Singleton It would allow you to access/manipulate the data fairly easy from anywhere.
The last 2 methods would insulate data from user interface controller objects and prevent the need from potentially unrelated objects needing to hold references to one another. Used properly it will reduce code complexity and mage future changes easier to manage.
Create an NSMutableArray property on your UITableViewController class like so:
#interface CustomTableViewController : UITableViewController
#property (strong, nonatomic) NSMutableArray *dataFromOtherClass;
#end
And then when you transition, perhaps like this, you can set the dataFromOtherClass property:
CustomTableViewController *controller = [[CustomTableViewController alloc] initWithNibName:#"CustomTableViewController" bundle:nil];
controller.dataFromOtherClass = myNSMutableArrayData; // <-- Set data like this
[self.navigationController controller animated:YES];
// Or ...
[self presentViewController:controller animated:YES];
// Etc...
I have a UIViewController in my iOS application that displays a table that is derived from an NSMutableArray. The cells in this table each refer to a unique UIViewController that is called when the user makes a selection. What I am trying to do in my "didSelectRowAtIndexPath:" method is to dynamically create the UIViewController via an NSMutableDictionary that contains keys that match the values in the NSMutableArray that the table is built from, as well as values that contain the corresponding Class names for the respective UIViewController that needs to be called. Because the list is rather long, I figure I need to do this using a for loop, but I am a bit confused as to how to do it. My NSMutableDictionary looks like this:
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setObject:#"aViewController" forKey:#"SelectionA"];
[dict setObject:#"bViewController" forKey:#"SelectionB"];
[dict setObject:#"cViewController" forKey:#"SelectionC"];
and my NSMutableArray that is the basis for my TableView looks like this:
NSMutableArray *myArray = [[NSMutableArray alloc] initWithObjects:#"SelectionA", #"SelectionB", #"SelectionC",...,nil];
How would I obtain a reference to the value inside the cell, and then construct a for loop that would dynamically create the correct viewController that corresponds to the selection made by the user from the tableView, and then take the user to that viewController via the navigationController?
Thanks in advance to all who reply.
Its not a good idea to create many ViewControllers, you should create one ViewController,
and pass the value of they tableCell to it. In other words, you change the data modell of the ViewController, by selecting the cell. But you will present the Same ViewController.
Only in the case that your cells coreesponmd to different types (e.g one cell a road mao, another a text value) , you have to call different ViewControllers.
If you realy need different view contollers, then get the type you want to dispaly from the cell data
in didSelectCellRowAtIndexPath
myAppDelegate *appDelegate =
[[UIApplication sharedApplication] delegate];
UIViewController *viewControllerToDisplay;
switch (selection.type) {
case MapType:
viewControllerToDisplay = appDelegate.mapViewController;
case Picture:
viewControllerToDisplay = appDelegate.pictureViewController;
}
now push viewControllerToDisplay to navigaton Controller.
If you really need a view controller for each cell, there's no need to use a dictionary to look them up. Since selection will be by index path, an array is a better choice.
Create a custom object that has two properties: the name you want to display in the cell and a pointer to the view controller you want to push when it's selected. Load myArray with these objects instead of strings. When you are populating a cell, select the object that matches the row and use its name. When a cell is tapped, select the object that matches the row and push its controller.
(But, as others have said, if you can use the same controller and only change the data, that's the way to go!)
Here is the solution,
If you know the name of class then store all the classes name in array with dictionary having key ClassName and Xib. I prefer plist to store names but you can use other way also.
And at didselect of table or picker place the code like this,
Class classobject = NSClassFromString([[ClassArray objectAtIndex:row]valueForKey:#"ClassName"]);
id object = [[classobject alloc] initWithNibName:[[ClassArray objectAtIndex:row]valueForKey:#"Xib"] bundle:nil];
[self.navigationController pushViewController:object animated:YES];
First line will convert your string to class.
Now as we have a benefit that id can hold any object so creat the object using id. And finally you have a custom class object you can do whatever you want to do with it,here for just a demo I did navigation.