I'm working on a app that is written with swift3 in Xcode8.
My app implements the Cosmicmind-material-framework.
While the working i tried to understand what the difference between NavigationController and ToolbarController is. (maybe someone can additionaly explain the difference to PageTabBarController, too)
I don't really get it because it seems that the navigationController contains a toolbarController.
So why should i use both if i can only use the navigationController and prepare all "toolbar-items" there.
Shortly to the app:
NavigationDrawerController
NavigationController
Site 1
Site 2
PageTabBarController
Site Red
Site Blue
Site Yellow
good question.
The main difference between a NavigationController and ToolbarController is that a NavigationController is a subclass of UINavigationController and gives you all the benefits of that class while allowing you to customize the look and feel as if you would a ToolbarController.
The ToolbarController provides a different type of flow, one that transitions the rootViewController using the transition method between view controllers. It also provides a floating view controller that can effectively be used in many ways.
Like the ToolbarController, the PageTabBarController inherits from the RootController, which provides the same rootViewController transitioning, but by default offers a UIPageViewController as the initial rootViewController.
So what is the point of all these different controllers? The main design reason is to allow you to stack view controllers that have these special controls in order to create more complex navigational architectures without the fuss of maintaining their organization. Each is accessible within the hierarchy while managing their own code complexities. The user has the perception that they are all working together seamlessly.
A good example of this is the CardTableView sample project, which also shows how to layout Cards within the PageTabBarController using TableViews that have dynamic heights based on content. For the most part, the entire UI is driven using persisted data powered by Graph.
Hope that helps :)
Related
I am working on a todo app that interacts with an API to store data. My view structure looks like this (simplified):
ContentView: List of { ProjectView }
ProjectView: List of { TaskView }
The ContentView has a webServer variable that provides functions like storeTask(task: Task) and deleteTask(task: Task).
So now I want my TaskView to be able to modify tasks. The most straightforward pattern seems to provide storeTask and deleteTask to TaskView to keep the view ignorant of the implementation details. That means that I have to pass these two functions through the whole tree of sub-views: ContentView -> ProjectView -> TaskView. But then, a minor change in function signature requires a changes for every view that's part of the view hierarchy.
This feels like an inefficient pattern as it's already complex for the simple app I am building. What are other approaches? For context, I remember this same issue from working on React, and using approaches like Redux to deal with this. I'm wondering whether there's a standard approach for simplifying this in SwiftUI?
The most common architecture pattern in SwiftUI is MVVM (Model-View-ViewModel). There are many articles online explaining it, but essentially the layers break into:
Model - manage a piece of data
View - manage the UI
ViewModel - manage the data (models) to be displayed in the UI (view)
To answer your question, you would need to create ViewModel layer that manages your data and pass that ViewModel throughout your Views (as #Asperi mentioned in the comments).
Here is a great article explaining MVVM: https://matteomanferdini.com/mvvm-pattern-ios-swift/
Here is one of my Github repo's that uses MVVM Architecture in SwiftUI to make a todo-list app, similar to your project. If you take a look at the ViewModel layers you will find examples of what you're trying to do. https://github.com/ndsarno/TodoList-MVVM-Advanced
I have an application scheme implemented in Ember that basically follows this layout:
The concept is that the user can interact with features on the Map View (which is always present) and basic navigation occurs between various views in the Parent View and an arbitrary stack of Sub Views. The user can create new features on the map, edit existing ones etc.
The URL for a particular feature could be /features/123/edit
Since input into my interaction panels is very much dependent on interaction with the Map View (drawing a polygon, placing a marker etc.) my controllers for these views are setup to "need" the Map Controller. When a particular panel view is present interaction with the map should affect the panels in various ways.
My question is - how does one scale such tight controller coupling? I essentially need to switch between different Map modes based on which panel is currently active. I also, I believe, need to observe events on the map and act upon such events depending on the current active panel.
I setup a proof of concept where a certain Sub View Controller observes certain properties of the Map Controller (with for example .observes("controllers.map.activecoords") however, such an observer will continue to trigger even after the user has navigated away from the particular Sub view (i.e. as soon as the controller has been initialised). Must I setup and tear down such observers manually (i.e. using addObserver) when entering and leaving the route? Is this the right pattern? I've gotten the impression that requires that I manually remove all such observers during transitions to avoid unexpected behaviour and memory leaks.
Perhaps I'm going about this completely the wrong way? Are there any others patterns that fits my use case with an always present map with different states and intercommunication with interaction panels?
Perhaps the architecture of your application shouldn't be connecting controllers, but rather ask yourself "What is the model here, really?"
In each case, I think the model is your map, or at least its "contents". The features are really decorating the interaction with your central model, which is the map, underlying it all.
So really you have a single model here. You effectively have a map resource, and many feature routes on that resource, viewed from the URL/API.
The question is now not so much "how to manage a dependency hierarchy between controllers?" as "how do I manage a view and a subview on the same model?" which is answered quite simply in the standard ember nested route. Your outer view is always present and it has an outlet which is where your feature goes. How it's rendered is the inverse of how the standard nested route is rendered, but nevertheless it's the same pattern.
So, the TL;DR answer is... go through your model and the routes... use them to talk about your common data: the model is, afterall, your data, and the controllers and views are simply augmenting and enabling the user experience, presentation and interaction of them.
Most of these sorts of architectural problems can be resolved by moving the data up and down the hierarchy (template view / component / controller / route / model) until you find a place which is low enough to still be accessible to objects that need access to it, yet high enough that it makes sense by not being tightly bound with too many things, but still is in the right spot and "feels right".
If it's too high, you'll tend to be doing the wrong kind of work with your objects (ie controllers should not be mucking with view mechanics, models shouldn't really have presentation stuff in them, etc.
If it's too low, you'll tend to be doing too much work with the framework and you'll tend to be repeating yourself a lot... ie controllers will be doing a lot of work to get the data they need, for example.
I seem to be getting more and more confounded at what appears, on the surface at least to be pretty basic architectural questions regarding building ember apps.
Which Controller type?
In the last month or so, I've seen people implement controllers through Ember.Controller, Ember.ArrayController, Ember.ObjectController, and Ember.ArrayProxy. Removing ArrayController and ArrayProxy (due to them being identical), what are common use cases between each type?
So far, i've been able to gather that:
ArrayControllers/Proxies should be used when you have n elements within the view you intend to control
ObjectControllers should be used when the view is simple enough to maintain it's state in a single object, or be a single instance of a model's object.
Controllers --- ? No idea.
What are some basic differences between the controller types? There doesn't seem to be concrete information on when to use which, and for which use case. The API docs are good at telling me the nitty gritty of each of them, but not WHEN to use each.
The relationship between a View and a Controller can be baffling
When a View is connected via a routes ConnectOutlets function call, what exactly happens between the controller and the view?
Are events tied into the view itself (which seems to be the case) and if so, where on earth do you interact with the controller singleton to perform CRUD-esq things on its properties? this.get('controllerName') doesn't seem to do the trick, and nearly each post or tutorial or code sample out there does this a different way.
Models that aren't
I realize that Ember Data looks to help solve some of the more irritating parts of dealing with data and keeping it in sync, but at a larger perspective, in the concept of "MVC", ember doesn't really seem to have a Model of any kind. It's just some object that gets subclassed from a specific thing and then tracked....somewhere? Somehow? Magical?
#trek sufficed that an Ember.Object could manage ajax'ing data and handling state on the client just fine, but if you look at something like the todomvc.com ember app, it uses a localStorage paradigm that is COMPLETELY different in implementation then everything i've looked at.
How EXACTLY should the 'Model' part of the MVC equation be done here?
Views make me want to murder children
There seems to be a significant number of ways to construct a "view" in terms of displaying markup to a user.
ContainerViews, using subviews / childviews
nested outlets
Handlebars templates + an outlet
using #each foo in controller
Injection through literals (template: Ember.Handlebars.compile('<h1>foo</h1>') etc)
With that in mind, what's the 'proper' way to build modular UI components with ember? This more than anything is a major pain point for the adoption of this framework for me.
I love the direction that Ember is going with application development on the web. The concepts seem simple, but the verbosity is that of Objective-C (which makes sense given it's lineage) but I swear to god I feel like i'm fighting the god damned framework more than i'm actually working on my application. The verbosity of the syntax and the lack of structured documentation outside of API documentation (which lets face it, 300k of javascript is a significant amount of code to throw some breakpoints down and try to debug your issues).
I realize the challenge that you guys are up against, but hopefully this at least makes you pause for a minute and think of how you could make life easier for the incoming developer who's worked with other frameworks (or hell, even worked within an MVC framework, like rails or django or backbone or angular) and say "this is how we think ember should be used".
Take some of the opinionated software design decisions and apply them toward the community. We'll do nothing but be cheerleaders for you if you do it, promise.
Please don't hurt any children. AFAIK the ember-core team are all over 18, so any ember-view-related frustration is clearly better directed towards adults. With that in mind...
Which Controller Type?
You've got the "what" right, but maybe missing the "why". Controller can be a little misleading, especially coming from rails. Think of these controller singletons as representing the state (in-memory) of your application.
Which kind of controller to use depends on what is required for that part of your application. For example, a back-of-napkin sketch for any app might have a topnav, postList, postDetails section. In ember, each is represented by one or more view/controller pairs. In this app I would expect to see ApplicationController and NavigationController extending Ember.Controler while postList would extend ArrayController and PostDetails would be an ObjectController.
You could do it all using just Ember.Controller but ObjectController and ArrayController are really useful for wrapping model data. Any non-trivial ember app will probably use all three.
The relationship between a View and a Controller
A controller's job is to provide the context in which the view will be rendered. Ideally you'd like to keep logic out of views, so a typical controller will have lots of computed properties to do things like:
transform data from the underlying model objects
sort/filter/select a list of objects
reflect application state
whats the deal with connectOutlets? This is where you should be using the requested route/context to decide which views/data should be plugged into the outlets of your application. The controller's connectOutlet method has a bunch of magic to make it easy, but maybe too much magic. What happens (afaik) when you call: parentcontroller.connectOutlet 'child' is
Ember creates an instance of ChildView
The {{outlet}} handlebars helper in parentController's view is bound to this childView instance
The childView is rendered with the router.childController singleton as it's context
where to do crud stuff?: Typically in an action on the router. This seems crazy at first. Think of ember router not like rails but as a stateManager that just happens to also handle routing. In near-future router API will change to make this more clear. Anyway, use router actions to do things like create model instances, commit/rollback transactions and trigger state change. This is easy to do if you use the handlebars {{action}} helper for links/buttons as it targets the router by default.
Views on the other hand should have logic for "reacting to browser events" - that means really low-level stuff like show/hide something on mouseover or integrate with 3rd party libraries to do effects and animations.
You might find this screencast helpful in understanding how to do CRUD-esq things:
http://blog.bigbinary.com/2012/09/06/crud-application-in-emberjs.html
Models WTF?
Agreed in Ember any object could be used as a 'Model'. I think #trek does a good job of demonstrating how one might accomplish this via Ember.Object. This works great for a simple app, and six months back maybe would've been your best bet as ember-data was really immature. I'm not clear on the history of ember's todomvc app, but for sure it was written months ago. For sure it should be updated, but meantime I'd not recommend using it to learn about current ember best-practices.
Instead, you should go with ember-data. Over the last few months it has really evolved and should be the default choice for any new, non-trivial ember app. #tomdale just gave a great presentation on this topic, I'd recommend having a look: https://speakerdeck.com/tomdale/ember-data-internals
what's the 'proper' way to build modular UI components with ember?
For building modular UI components:
ContainerViews, using subviews / childviews
Injection through literals (template: Ember.Handlebars.compile ...)
For building an individual application:
nested outlets
Handlebars templates + an outlet
using #each foo in controller
Building modular UI components is a totally different problem than building an application. Ember.View and it's subclasses were designed for this purpose. You can easily extend/combine them to compose widgets with custom behaviors and share those widgets across applications.
At least that's how i've seen it done. If they are for internal use could also reference handlebars templates instead of object literals, but if planning to distribute the object literals approach seems best.
A great real-world example of this is the ember-bootstrap project. I learned a lot about working with ember-views by reading through that project's source. http://emberjs-addons.github.com/ember-bootstrap/
TLDR
Pick controller that maps to type of data being represented
Controllers provide context for the view and remember application state
Use ember data for your models
Use subclasses of Ember.View to make components
Be nice to children
I'd like some examples please of how you use Ember.Controller objects. Apart from the StateManager, I really don't find myself using Ember.Controllers much at all. In the Ember source code it says that actions should be sent to the controller, but I really don't find myself using these so much, because I abstract the views so much, and therefore use the in-built actions like click, change, and keyUp. Am I abstracting too much?
For instance, if I'm displaying a button on the page, then I'll create a new Ember.View in my controller view, and then simply include that on the page.
Most direct interaction with controllers is indeed through the StateManager/Router. The controller's main responsibility is to present data to the views for rendering. They do this by proxying to models as well as maintaining transient state.
You are also correct that a single controller can often be responsible for a hierarchy of views.
I recently did a talk about the responsibilities of various layers in Ember apps. Slides are here: http://www.lukemelia.com/devblog/archives/2012/08/23/architecting-ember-js-apps/
This website has a pretty good presentation of how to use each part of Ember's MVC, and their relationship with each other:
http://www.lukemelia.com/blog/archives/2012/08/23/architecting-ember-js-apps/
Are controllers in ember.js meant to be tied to main view areas/scenes a la iOS, or more tied to a set of data?
Is it common/wise to have several main views tied to the same controller in ember?
In iOS main portions or sections of the screen are tied to a single controller. If you want to present another main interface, say a modal window to create a new element, you (typically) have an entirely separate controller to manage that view and its data/logic.
In something like Zend Framework, you have controllers that might perform some common spinup steps of ensuring authentication, but largely the actions play the role that controllers do in iOS, handling the logic and providing the data for 1 main section or view (being the web, this usually ends up being the whole page).
What is that typical role or advised pattern for using controllers in ember?
You have a couple different questions here so I'll address them one at a time.
First, you asked if controllers should be data oriented or view oriented. In my experience both behaviors are allowable. Controllers are an excellent way to manage data sets for your application, including things like filtering and searching. Evin Grano wrote a good post about this from the SproutCore perspective and most of the concepts should apply to Ember as well: http://www.itsgotwhatplantscrave.com/2009/07/30/root-controller-paradigm/. Controllers are also well suited for controlling the application state and behavior. For example, you might put a method in a controller that is bound to as a button action elsewhere in your app. However, you should also examine Ember States to see if these might be better suited to your scenario.
Secondly, you asked about tying multiple views to the same controller. Personally, I see no concerns with this as long as the controller maintains a distinct purpose. If the views are logically related and share in the same state or data then a single controller makes sense. If you find the controller growing to cover too many different areas, you should consider splitting it into multiple controllers.
From my limited experience in Ember.js, I have regulate to the following:
The view handles user actions related to changes in the presentation layer, limited to its own instance.
A navigation controller/statemanager handles complex manipulation of what is presented (add multiple views, remove some other, etc.).
The controller responds to user actions related to the data layer.