ios/iphone sdk form management best practices - ios

I'm working on an iPhone app that will have involve a lot of forms. Currently I have a ViewController class for each settings page which has an UITableView loaded with possible settings. When someone clicks on a setting they are taken taken to a new view to enter the form value, or allowed to enter things in place.
What's the best way to keep things DRY? What pieces of this implementation could be implemented once and re-used?
When someone clicks on a settings option which goes to a new view how can I create this view and add a text field according to the data type (uitextfield or picker or something else) in code?

You can programmatically:
create view hierarchy
UIButton
UILabel
You get the idea.
However, I would recommend getting your logic working for a few of the cases, and then it should become obvious what parts are redundant as you find yourself typing in the same thing over and over. At that point, refactor to get the redundant code into a re-usable form.
HTH.

If you have a tableView, the flow is to create the viewController of the selected settings in the didSelectCell method of your tableView delegate and to push it through the current viewController's navigation controller.
here's a sample:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.navigationController pushViewController:[self settingsViewControllerAtIndexPath:indexPath] animated:YES];
}
so you'll have to implement the method:
- (UIViewController*)settingsViewControllerAtIndexPath:(NSIndexPath *)indexPath;
wich will return the viewController managing the settings associated with the selected row of your root tableView.
If your forms are pretty statics, you should consider using a xib in order to minimize the amount of code needed. it isn't a perfect answer to your "how to keep DRY" but it's neat enough ;)
Good luck.

Related

How can I give a particular behavior to a UITableViewRowAction?

I have a standard UITableView of items. Tapping a row will bring a DetailsViewController with details about the selected item and the possibility to use it through a UIButton.
I have implemented the (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath method made available from iOS 8 and I defined two actions:
The standard deletion of the item (pretty simple stuff).
The possibility to use the item like above. I basically want this action behavior to be the same of the IBAction related to the button in the DetailsViewController.
I thought about presenting this view controller automatically and making an automatic tapping of the button without using interaction, but this could be a bit confusing for the user according to me. So I would prefer to call the IBAction method directly from the table view controller. Is it possible and how can I achieve this result?
I can provide the source code if this could help you to help me.
What you need to do is take the "use this thing" action out of your ViewController, and put it in the Model object for "thing."
Then, when you want to use your "thing" from the tableView or the DetailsViewController, you can call this function directly on the associated model object, and allow your two (possibly more) different user interfaces to perform the "use that thing" functionality appropriately based on their own UI needs.

Segmented control to toggle through multiple tableviews

What I’m basically trying to is to implement the control segment/tableview as in Mailbox (see it around 2:00: http://www.youtube.com/watch?v=FG-h8pDXfoE&feature=youtu.be&t=2m)
I am using Core Data in one UITableViewController hooked up to a UITableView.
When user toggles the UISegmentedControl, the TableView is reloaded with a different set of NSPredicate, and UITableViewRowAnimationRight/Left, kind of makes it appear that that a different table view slides in and replaces the old one.
As the number of cells increase, the performance of this design decrease dramatically, and it could also look much better.
I can see a few different ways of going about it, but I figured I'd ask you guys for some pointers to head me in the right direction:
What is the best way to have a segmented control to toggle through multiple tableviews? Should these tableviews be connected to the same data source/delegate?
Take a look at this pod: https://github.com/xmartlabs/XLMailBoxContainer. It makes the UI animation among the view controllers. These view controller can extend UITableViewController or any other view controller.
UITableViewCell swipe animation can be accomplished using https://github.com/alikaragoz/MCSwipeTableViewCell.
I hope this could help you!
It really depends how different each of these table views is. If they are quite similar, it's probably easiest to just share the delegate and data source and have some conditional code.
In fact you can just have a single table view, but have different cells / configuration depending on your current context.
Could be as simple as having adding some conditions to
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
Another approach would be to use view controller containment. You would create a UITableViewController for each and then have parent view controller with segmented control which swaps child view controller accordingly.
As for the animation and performance, I can't really see any problem. You can get the animations without much effort if you use NSFetchedResultsController, see an example here: https://developer.apple.com/library/ios/documentation/CoreData/Reference/NSFetchedResultsControllerDelegate_Protocol/Reference/Reference.html.
See SBSegmentedViewController. I wrote it for exactly what you're trying to do.

Embedding UIViewController view inside another UIViewController

In my app, I have a login-register-forgotpasword wireframe. Each step of the process is implemented in a separate UIViewController, all of them inside the same Storyboard, and transitions between each controller are animated. So far so good.
Now we've changed the design, so all views have the same background elements and a header (not exactly a UINavigationBar), and I don't like the feel of the animation to a view that always looks to be actually the same, but just showing a different form. So I'm considering different approaches to, instead of pushing whole controllers, just showing/hiding its views, but staying in the same controller.-
1) My first try was instantiating the controller which view I want to show, and add it to the current view. Something like.-
- (IBAction)btnRegisterPressed:(id)sender {
_viewHome.hidden = YES;
RegisterController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"registerNewUser"];
[self.view addSubview:controller.view];
}
This one would be perfect, as I'm using static UITableViews for my forms, so as far as I know I'd need a UITableViewController for each one. But it seems IBOutlets and IBActions got broken. Is this approach possible in some way? If so, it's considered a bad practice?
2) My second option is just creating all the views inside one controller, and properly showing/hiding them. This would one be hard to maintain, and chances are I'd have to forget about static UITableViews.
Could anyone give me some advice of which option would be better, or point me to any other possible approach I'm missing?
Your option #1 is not appropriate as written but close to an approach you should probably consider. You can add nest the views of different UIViewControllers however when you do so you should use the methods described in Managing Child View Controllers in a Custom Container so that the parent controller correctly manages its child controllers.
You can use as many tableviews as you want for the same controller. The delegate methods contains the object that fired the method itself.
Following this approach (which i wouldn't recommend) you can probably tag your tableviews and then do:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
if (tableView.tag == 1) {
doStuff;
} else if (tableView.tag == 2) {
doOtherStuff;
}
}
Well, personally, I feel we should keep things simple and straight forward for end user to quickly gel up with your app. Animations plays an important role in this. Tapping on cell of a tableview pushes another table view and there are different UI widgets like chevron that indicates the transition and user is not surprised.
Showing everything on single screen and hiding/unhiding them based on user's action is fine as long as you have proper animation. For instance, you might have seen TableView sections collapsing/expanding on tap.
You need to make a trade off and see what best suits based on your application. Whatever you decide my suggestion would be to add nice animations instead of simple hide/unhide.

UITableView inside UIViewController not displaying

I am trying to set up a UITableView inside of a UIViewController. I'm doing this because it allows me to add a top bar with save and cancel buttons. I'm using storyboard and static cells to model the tableview to get input from the user (think of the create new event in Apple's calendar app). I have the view in Xcode, but when running it on my phone or the simulator, the tableview does not display. Here is the simple view in Xcode:
And this is how it displays when running it:
I've read about adding delegates and setting the datasource and such, but really this is all just going to be static cells with text fields, no data being loaded. Why is this happening and what can be done to fix it? Thanks!
#Made2k It looks like you found a solution, but for others who come across this with the same issue, note that you can only use a UITableView with static cells inside of a UITableViewController. This is not a well-documented fact, but apparently only UITableViewController knows how to handle the layout of static cells, whereas a regular UIViewController just needs to implement the UITableViewDelegate and UITableViewDataSource protocols in order to handle display of content in a UITableView added either programmatically or via Storyboard/Nib.
Hopefully this will save someone some time. #Made2k's solution is fine, but does make your storyboard unnecessarily busy. If you don't need to use a UIViewController, then just do your work inside a regular UITableViewController and save yourself a headache.
If you want to use a UITableView in a UIViewController you have to make the ViewController a data source and a delegate of the TableView and then implement methods
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
In case of a static table, in the cellForRowAtIndexPath you'd return outlets of the static cells. For a detailed description check out this answer:
https://stackoverflow.com/a/19110821/3110536
I ended up thinking about this in a different kind of way. The problem I thought I was having was I wanted all the features that a navigation controller provides, but I needed this to be the base of the controller, i.e. nothing to go back to. I was thinking that the only way to do this was to create a UIViewController and add the table view and such in there, but what I came up with is to simply just create a new navigation controller and now this view shows up as the root view like so:
I don't know if this is the best practice, but hopefully it can help somebody else if they are having this problem.
Man, following Hack really works!
You should give it a try!
In my requirement I wanted to add buttons in my Static cells too!and Toggle the visibility of the TableView
[self.tableView setHidden:YES/NO];
and Reload it with new data
[self.tableView reloadData];
and so many things is possible with that way of doing it!
https://stackoverflow.com/a/19110821/1752988
Hope the above link would help you! (Y)

How to separate ViewController methods between X files

I've started to develop for iPhone just 1 week ago, things are going very well, but I don't know even how to ask this question (english is not my natural language), let`s see if you will understand me.
I have a ViewController that do many things. Show some images, do some animations, scroll the images while change the white dot from Page Controller...well, this kind of stuff.
But my ViewController.m have SO MUCH code for just 1 file. Well, not YET.
What I want to do is to create another files in which I could write moar code, improving readability and organization. Like this:
ViewController.m (ViewController general code)
ViewController_Navigation.m
ViewController_ImagesScrolling.m
ViewController_DBActions.m
With their respective header files, if needed.
So, any ideas or examples of how can I do it?
The separation and encapsulation of function into separate classes is a common concept to break down masses of code. Methods that all have to do with one task can be lumped together as objects, usually UIView subclasses of some sort, or UIViewController subclasses for larger tasks that deserve their own screen of information. For example, you might have one that handles scrolling of images on its own once it's set up with the required UIImage's. Beyond that, however, you shouldn't generally split up a single controller's code. The controller contains all of the glue that holds the views it displays together along with the model in the MVC pattern. Thus, once all of the functionality that isn't reliant on the model has been sectioned off to views and you've partitioned the functionality into separate controllers in your interface, there is little you can do.
I would not recommend splitting the code into separate files because it all has one purpose: to coordinate what is going on on the screen and allow the views to interact with the model. However, what I usually do, is categorize and sort my code depending on what task it is managing. So, all of the life cycle and normal methods can go a the top, followed by all the table view methods, image viewer methods, etc.
This makes it easy to find code related to specific tasks, and even easier with the help of the pragma directive. Outside of any methods, in between your sorted groups of methods, you can use a pragma mark to assign an identifier to a location in your code, accessible through the jump bar, like I've done in the following example code.
#pragma mark - UIViewController Lifecycle Methods:
- (void) viewWillAppear{
//stuff
};
- (void) loadView{
//stuff
};
#pragma mark - UITableView Delegate & Datasource Methods:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//stuff
};
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
//stuff
};
Now, if you were to go to the jump bar at the top of Xcode's code viewer and click on the right most object to find a method, you'd see this:
I don't believe that after sorting your code, marking it with pragma marks and separating all the code you can into other UIViews and UIViewControllers, you should feel the need to split your code into several files; you can just use the jump bar to go to any section of your code, effectively like swapping files would let you do. However, this way, you aren't fragmenting code from one class and leaving bits and pieces all over the place.
iOS is based on the MVC model. Hence you should be using the controllers for managing the model and views.
Ideally I would be doing this:
a. Implement separate controllers for managing
1. Images -> separate the views for displaying images
2. Database
3. whatever else you have...
b. Implement a separate controller for managing the above controllers.
You need to add more objects/ controllers class for the single view/xib.
And each one of them will be assigned/linked to your class.
-This is quite frequent design pattern in OSX, I hope this is even valid with ios.

Resources