I have a quick question in regards to my app that I am developing for school. In my app we have 5 unique games that the user can play. However, each game has 2 modes, normal and hard. What is the best way about going to do this. Currently I have my first game as two separate view controllers and are called based on the difficulty that is wanted(one called normal_cstars and hard_cstars). I am wondering if this is efficient because each view controller has a .h, .m, and a .xib. Is it possible to have a view controller that has two separate views and how would you go about accomplishing this.
Thanks,
Ryan Wong
Of course. You can pick which one of the two views you display inside your viewcontrollers. Just send self.view in the view controller to be the view you'd like to use.
One way to architect this is to have two separate view classes that share the same controls. The controls are all handled by the view controller while the views each draw their own layout.
And don't be worried about sharing subviews among the two main views -- or you can keep your two view controllers, and just have shared classes that make up the views and controls of each view controller's presentation. Just because you have two view controllers doesn't mean you have to have redundancy code. Split things out into separate classes, from your animated views to your controls.
There are a lot of other possibilities. Look at some of Apple's samples to see how multiple view controllers are used.
Do you really think that you need two separate views? (I am not sure about your game though)
Since game modes are Model specific, a model with behaviour "Normal" or "Hard" will actually render the game in a view.
If near future, if you want to implement a mode "Easy" then you end up with another view controller and might encounter code redundancy.
Solution I would think:
Create a inheritance over composition pattern for your model objects.
A view controller will be much more generic and tells view to render based on the mode
Now the base class of the model will implement generic methods and since the model has mode as composition, the view will render the game objects based on it.
Advantages? - well we have not violated the Open-Closed Principle.
And again there are various design patterns out there to achieve this. Its up to you to decide which suits the best for the requirements.
Related
I'm having a problem with the app I am developing right now : one of my UIViewControllers is huge ( around 3000 lines ).
For now, I created extensions of this view controller to handle delegate methods in order to "split" this controller. For instance, I have my main view controller called XYZMainViewController and as this controller is the delegate of a UITextField, I created an extension XYZMainViewControllerTextFieldDelegateExtension.swift in which I manage UITextFieldDelegate methods.
It's still pretty dirty to do that this way. I'm wondering what would be a good practice to handle huge controllers like this one.
did you consider to design your app using MVVM (model view view model) the idea of MVVM is to avoid huge controllers. There are a lot of user guides out there which explain how to use MVVM in your IOS app. I was facing the same situation half a year ago and then i adopt MVVM in my app and i am very happy with it since my controllers are not huge, i can reuse code easily in my app and also it's much more easy to create unit tests.
Please follow this guide which explain what is MVVM and how to use
ithttps://www.raywenderlich.com/74106/mvvm-tutorial-with-reactivecocoa-part-1
https://www.raywenderlich.com/74131/mvvm-tutorial-with-reactivecocoa-part-2
3000 lines is hmmmm hugeeeeee.
You have performed huge numbers of tasks in your controller. Controllers are supposed to control views.In my opinion(the way i create my iOS app structure) controller is suppose to perform view control,passing data from models to view(more specifically from classes which manipulates data).
"Separate of concerns" is important here. Don't implement your business logic inside controllers. There should be a separate module which do all of your business logic. How to manipulate models and complete a functionality. Then this class is used by controller to perform view updates.
No matter what type os view you have designed ,its controller can't be of 3000 lines. Delegation is not a problem. Controller is a good place to do delegation. Inside those delegate methods ,to perform some business is not the work of controller. There are some design patterns for IOS apps like MVC, MVVM.
But still you have to use "these design patterns efficiently. move the common functionality in one place etc. Implementation of business logic. Manipulation of models. Communication with DataBase.
Thanks.
This is probably largely preferential but I'd like to know if there are any reasons to decide one way or another on this.
When designing with storyboards you invariably end up with a number of view controllers. I'm looking at the overhead of a strict MVC approach where each controller is implemented in its own UIViewController subclass with corresponding UIView subclass (and even view model class for MVVM), and that seems to get out of hand quickly – it takes no time to add dozens of files to the project (many with little function). An alternative approach would be to link all the views to a common controller representative of all of the storyboard functionality.
My inclination is that if you don't have substantial controller code for any individual view controller, then the combination of all of them into one shouldn't be of harm to the readability of the code (and may enhance it over adding a large number of source files). On the other hand, if you have significant functionality to implement for any particular view controller, then it should be encapsulated within it's own controller.
In most situations I'd build all controllers to be as reusable as possible (encapsulated in their own custom UIViewController subclasses). Storyboards put this in an interesting light though since they seem to be geared towards sequences of views that typically have few entry points.
Your thinking is correct
If you don't have much functionality in each VC (ViewController) them combine all your code into one VC. The only drawback to this approach is that you won't be able to implement view specific code and every view where you will use this common VC will execute the same code whether its needed there or not. e.g. code in viewWillAppear etc.
Similarly if you have a lot of functionality for a particular view then its better to put it under its own VC
This is just a suggestion, if you need to use some common code logic between multiple VCs then instead of doing copy and paste in each VC of the same code, make it into a method of type Category and then call it where ever its needed. So change the code only at 1 place.
More VCs doesn't necessarily mean bad design. In my opinion its easier to maintain that way. My two cents. :-)
Each scene in your storyboard should have its own UIViewController subclass. Even doing it like this it's way too easy to get huge unmaintainable view controllers (MVC = Massive View Controller). Putting all the code for multiple scenes in the same view controller would create even bigger ones and also violate the Single Responsibility Principle. Each class should do only a single thing.
That also means you shouldn't duplicate the common functionality into all your UIViewController subclasses. Then they again would do multiple things - the common stuff and their actual purpose. Instead you can put your common code in other controller objects (which are not descendants of UIViewController) and use them in your view controllers.
Depending on the usecase a common base class would work as well, but it's always preferable to use composition instead of inheritance.
Another nice thing about other controller objects is that you also can add them directly in Interface Builder and connect actions and outlets to them. Your main view controller class often doesn't even have to know they exist.
I'm all for trying to create lightweight view controllers (testability, separation of concern, etc. etc.), however, I've been unable to find a reasonable solution or pattern when it comes to certain cases.
A very common case (with plenty of examples out there) is separating the view controller from a tableview's delegate & datasource; I get this, it makes complete sense. But what about cases where a view controller may contain multiple custom views of varying complexity? What should be responsible for controlling each of those views? Surely not just the parent view controller.
I tend to think of a 'UIViewController' as more of a screen controller that is heavily coupled with the UI framework and its events; it does not have a single responsibility of controlling one particular view. To further illustrate my point, imagine a tableview with a couple of different prototype cells - some of which are fairly complicated and may require network access for instance - how should this be managed? Surely no single view controller, datasource or delegate should act as the "controller" for all of these cells? And a lot of that logic/responsibility does not belong in the cell views themselves, so it needs to be delegated somewhere.
One option I've thought of is to just create controller objects (subclasses of NSObject) that act as "view controllers" for the custom views I create, such as a controller object for a complex tableview cell - its single responsibility is to manage that one particular view. The tableview cell then delegates to the controller object, which then (if needed) delegates back to the parent UIViewController. Whilst this will work and helps to separate concerns, it starts to feel a bit awkward with all the layers of delegation going on.
Does anybody have any good suggestions on handling these scenarios or know of good code examples out there that demonstrates this?
Thanks!
I'm working on figuring out mvvmcross and if I can use it for an iPhone (and eventually iPad and Android) app I'm going to develop. The MVVM pattern is really powerful and works great for me, but I have several views where I need to add a navigation control that will allow the user to jump to several different other views and I'm wondering what's the best way to do it.
Right now, I've created a NavigationControlViewModel which exposes a collection of NavigationLinkViewModel which have a link text property and a command that will show the appropriate view. But to add this to a view for, say, MyViewModel is a little tricky. Right now what I've done is add the NavigationControlViewModel to MyViewModel so that I can bind it in MyView:
private NavigationControlViewModel _nav;
public NavigationControlViewModel Navigation {
get {
_nav = _nav ?? new NavigationControlViewModel (Mvx.Resolve<INavigationService> ());
return _nav;
}
}
This works, but doesn't seem as nicely contained as I'd like to be. I still need to add controls to MyView for the NavigationControlViewModel and then add it to every other view that needs it (as well as adding it to their view models).
What would be the best practice for handling this sort of thing in iOS and MVVM?
I've seen the video on using a split view, but I'm not sure if that's the best approach. I need a vertical split and I only need it on some views, not every view.
For sharing the navigation mechanism between view models, I guess you can use either aggregation as you have done NavigationControlViewModel or you can use inheritance with all the navigation items in a BaseViewModel class.
I personally would happily use either of those but would make sure to expose all my Navigation options as ICommands - simply because that's the way .Net-style data-binding generally expects 'action hooks' to be presented. Note that there is a reflection way of generating ICommand's - see http://slodge.blogspot.co.uk/2013/03/fixing-mvvm-commands-making-hot-tuna.html
For actually presenting the ViewModel via a View on the screen... I'd encourage you to believe that you can do whatever you and your UX/design team want to.
Some of the standard presentation approaches are available via: UINavgiationController, UISplitViewController, UITabBarViewController, UIPopupView and PresentModalViewController - and you are free to use these and to combine them together - e.g. you can have a navigation controller which two layers deep shows a modal view which contains a split view with two children...
Beyond the standard approaches, there are plenty of other UI design paradigms that people have selected:
flyout and flyunder views - like the hamburger menu
the Twitter iPad stacked view approach - like https://github.com/steipete/PSStackedView
heads up display views (dialogs)
continuous scrolled views
... plenty more - see http://pttrns.com/categories/13-navigations
By default, MvvmCross provides you with a 'whole page' presenter which presents every View-ViewModel pair the same way inside a UINavigationController. As you've seen in the N+1 video you mention, you can easily override that behaviour and you can then choose to present View-ViewModel pairs in any way you like - e.g. you can choose to present some whole page, some using a fly out, and then some using tabs.
Because an IMvxTouchView presenter is just C# code, and because we devs love writing C# code, we can implement whatever wonderful logic we want to within a presenter including code that tests what is currently being shown in order to determine where to show the next page.
I can't comment on what 'best practice' is for making a design look nice.
But I do believe that if you stick with showing your view models via ShowViewModel then that will allow you the most flexibility in what presentation strategy to use on each platform.
Some more on presenters is available via http://slodge.blogspot.co.uk/2013/06/presenter-roundup.html
I found this in SO; it doesn't exactly answer my question, which is: is there a way to clone a UITableView from one controller to another while using Storyboards and maintain synchronization?
You can clone them in the sense that their initial property values remain the same, like position, layout etc. For this, just copy the UITableView from storyboard, go to destination view controller and paste it there.
If you share same UITableView object between two view controllers, it is still possible, but you must estimate how much work you would have to do yourself. When a view controller solely handles a table view, much of the work is done under the hood and table is handed over to you. In case of your UITableView shared between two view controllers, you would have to play with it quite carefully. You need to take care of entire life cycle of the view - see the usual methods like viewDidLoad, viewDidAppear and so on. How would you take care of them when your view exists in two scenes? Maybe you would be inventing a unique design pattern - if at all you find the most optimistic and programmatically correct way to accomplish it.
With storyboards, you cannot achieve cloning up to the level wherein data changes will reflect seamlessly between the two. Storyboard is, as the name suggest, just a board, where you can draw things to know how would they look initially, before your code takes over.
In order to achieve what you want, you have to create a shared model that updates two table views through proper delegate methods. Most likely such a model (NSArray, or any such collections as per your requirement) can reside inside a shared class (app delegate isn't a wrong choice), from where both your view controllers can refer to it. That is neat practice, it not only is right from programming perspective but also extensible and helpful to anyone who deals with the code any time.
For details about how to update UI from your model, there is nothing better than starting from scratch, going through the books I mean.
I am not aware of such possibilities.
I would pass the tableview source object amongst different controllers and let the view controller handle their own table view.
I think the best approach would be to use a framework such as the freely available Sensible TableView, then use the same model for both table views. This should be really straight forward.