How to separate ViewController methods between X files - ios

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.

Related

6 separate UIViewControllers or just one with different data sources decided at segue?

I'm building an iOS app in Swift which has a start page with 6 buttons. Each of those buttons will segue to a table view controller whose data is managed with an NSFetchedResultsController (application uses core data). Now, I can see it being easy to create 6 UITableViewControllers however I'm wondering if it would be more sensible to send each button to the same UITableViewController and just change the data loaded/managed by setting some kind of flag in the prepareForSegue method?
What's the best practice here? It seems crazy to have 6 tableViewControllers each backed by it's own NSFetchedResultsController when big portions of the required code for each are reusable and could be subclassed out and used multiple times.
If you can code a single view controller in a way that supports all six with a single code base, reusing a single UITableViewController makes perfect sense. Other approaches include
Composition - make a class for the data source, configure it before opening the table view, and pass it to the table view on segue
Subclassing - make an abstract base view controller, and extend it six times. Override an abstract method or two to reduce the amount of repetition
Helper - make a class that holds all reusable logic shared across the six view controllers, and call its methods from six very slip controllers.
One thing you want to avoid is code like this:
if (viewControllerType == ViewControllerOne) {
doSomethingSpecial()
} else if (viewControllerType == ViewControllerTwo) {
doSomethingElseSpecial()
} ... // and so on
When you have a chain like this, you know that you've missed an opportunity to subcllass.
I don't know if this question will be closed as opinion-based, but here's my thoughts:
Definitely use only one view controller and changed the data source in prepareforsegue()
Imagine having 6 different controllers and then deciding in 6 months that you want to change the entire UI!!! I did that. Wasn't pretty. And that was the point when I reconfigured everything and scaled down my total number of view controllers.
And don't even get me started on the pains of having to do auto layout on multiple screens. You see where I'm going with this.

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.

How to set properties for more than one UITableView?

I have two UITableViews that I want to put into my app and obviously would need to set the properties of each of them (cellforRowAtIndexPath, numberOfRowsInSection).
How would I do this with two UITableViews?
Would I put an if statement (please explain) in these methods, or are there separate ways to do this?
If you are creating by IBOutlet set tag for each UITableview in properties window then if you want to set datasource
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
if(tableView.tag == 1)
{
return 1;
}
else
{
return 2;
}
}
same way set for cellforRowAtIndexpath.hope will help
Those are not "properties". They are methods; in particular, they are messages to the data source and delegate of the table view. Each table view gets to designate what object should be its delegate and data source. (Even those need not be the same object, but they usually are.)
So. If the tables are different, then why not have the data source and delegate of Table 1 be one object, and the data source and delegate of Table 2 be another object?
But if that is impossible, and both tables must have the same object as their data source and delegate, then yes, you will obviously need to distinguish one table from the other. That, after all, is what you typically do when you have a table and a search results table based on it.
To display two tables simultaneously you may be beter off creating two view controllers rather than distinguishing tableviews in a single controller. Do you really want to take small iPhone screen space displaying both the folder list and actual mail content at once? UI where controllers are pushed/popped has lots of advantages.
But if you want something different you may want to have a look at implementations of slide menu interface. That will show you how to implement two controllers visible simultaneously.
On iPad it is different and API provides a split view or master-detail interface.

ios/iphone sdk form management best practices

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.

Resources