I have a maybe slightly unconventional question. I'm working on an app that has two different core data entities (sessions and routines). Subsequently I have two different view controllers in interface builder to fill the attributes of those entities. The thing is that those two entities are identical aside from the fact that I need sessions to have a many to one relationship with a clients entity and routines to have no relationship.
The question is this. Id like to use the same view controller in interface builder for both my session and routine classes, is there a way that I can programatically determine what class the interface builder viewcontroller is assigned to based on a segue identifier? I know it would have to be some sort of if segue.identifier == "myIdentifier" {
/*code for changing destination view controller's class*/} statement but I'm not sure what the code would be, and I also want to hear other suggestions of ways to possibly do this more efficiently.
Thanks!
The view-controller in your Storyboard is an archived object of a certain class, and you can't just assign it to some other class. (Just as if you have a String object and want to assign it to be an Int wouldn't work well)
You can check the destinationViewController property of the segue within prepareForSegue: if it is a certain class like this:
if let dvc = segue.destinationViewController as? MyExpectedVC {
// do something
}
but that is probably not what you want/should do.
I'd go along the lines of what the commenters of your question have said and would suggest that your view controller class implements a configuration method for both your models. Either a separate one for each class like this:
func prepareWithSession(session: Session) {/* ... */}
func prepareWithRoutine(session: Routine) {/* ... */}
or (imho a bit nicer) create a protocol for all classes that can be displayed by the view controller and have only one method:
func prepareWithDisplayable(session: DisplayableType) {/* ... */}
where DisplayableType would be a protocol that defines all properties that this view controller needs to know about.
You can have custom logic in the view controller that displays some fields only for specific Types. (e.g. sets views hidden for other Types)
Related
I need to create the GUI for setting my app preferences. Since I am not able to get multiple instances of the SharedUserDefaultsController in multiple storyboard scenes, I created a simple proxy for it. I'm trying to bind a text field content to a specific values of the SharedUserDefaultsController through the proxy which is represented in IB via an NSObject added to the scene that should contain the binding. For the binding I use self.defaults.values.default_key where default_key is a defined key in the StandardUserDefaults for my application.
When I try to show the view that contains the binding, though, it is not shown and the only displayed message in the console is
Missing placeholder for identifier UpstreamPlaceholder-37m-v1-XT6
What am I doing wrong? In the storyboard source there's no trace of that identifier. Here's the code of the SharedUserDefaultsControllerProxy class that I created:
import Cocoa
class SharedUserDefaultsControllerProxy: NSObject{
var defaults = NSUserDefaultsController.sharedUserDefaultsController()
override init() {
super.init()
}
}
Being able to share data between multiple view controllers and doing that in a way that makes use of recommended patterns such as MVC seems to be essential to create good apps, but my problem is that these things aren't clear at all for me.
I am conscient that this question is really dense, but for things to be clear I think you really need to understand the whole thing.
First of all we need to be sure of what Model, View and Controller are doing, here is how I would describe them, please tell me if I'm right about that:
Model : a class that's responsible for managing data, and only that (for example, a class that will go on the web to retrieve information, such as weather forecast).
View : a view is an object that's displayed to the user, who can often interact with it, that's the objects that you can drag and drop in Interface Builder (for example a button) and you might also create one from scratch, or custom an already existing one by subclassing it.
Controller : a controller is responsible for managing a view and its subviews, it receives events (such as viewDidLoad, or even when the user taps a button) and can react to it, for example, it might change the text of a label.
Now about the way they are interacting between each other, I'd say that the controller is between the view and the model, it's managing the view and might ask for data to the model. In addition to receiving events from the view, it might also receive events from the model, for example, if the controller asks to the model for a specific data on the web (let's say if it asks weather for a specific city) the data won't be available immediately, instead, the model will notify the controller so that it can update the view with the data it received. Am I right?
One of the first thing I'm wondering is if an object could be considered as a model if it isn't here to retrieve data, but to do other things that are simply not related to the view, for example, could an object that's responsible for communicating and managing a bluetooth accessory considered as a model ? Could an object that sends data to a cloud considered as a model ? And what about a Tic Tac Toe AI ?
Then, singleton instances, I often heard of them when an app had to share data between multiple views, but first of all, I never really understood why it was necessary to use them in this case ?
Then, here is a singleton that I found in an article of the We Heart Swift website.
class Singleton {
struct Static {
static let instance = Singleton()
}
class var sharedInstance: Singleton {
return Static.instance
}
}
Singleton.sharedInstance
The problem if that I have had difficulties to find anywhere more details about why it's written in this way, and most of all, can a singleton have an initializer that takes arguments? How to add properties and methods to a singleton like this one? What are exactly the Static structure and the sharedInstance?
My last question is about why, technically, does a singleton makes it possible to get an access to things we have defined somewhere else? What I mean is that if I create an instance of let's say, a Dog class in my AppDelegate, and if I want to access to this specific instance in a view controller, then it wouldn't be possible, so how does singleton makes that possible under the hood?
EDIT : Oh, and, is the use of singletons recommended by Apple?
Thank you.
It has to do with the static in the struct. Static is essentially a class variable that persists for every instance of that class, so when you make the shared instance static, every time you access it, even from another instance of Singleton.instance it is the same variable because it is static. It persists amongst instances. However, Swift does not support class variables yet, so when it does, that should quickly replace the Struct syntax that is common of singletons. It is very similar to static variables in java.
For example:
class Singleton {
var someVar = 0
struct Static {
static let instance = Singleton()
}
}
to create a singleton with a variable and the following to access it:
let foo = Singleton.Static.instance
foo.someVar = 11
let bar = Singleton.Static.instance
println(bar.someVar) // Prints 11
As you can see, bar.someVar was never set, and that is because the variable for the shared instance was set, so it prints 11.
I am in the process of cleaning up my code as my TableViewController class has become rather full and long. To clean up the code, I would like to create a number of utility classes that provide methods for the TableViewController. These methods/functions, in my current implementation, are able to change variables in the main TableViewController. Here is an example of my current setup:
class FooImplementation: NSObject {
var viewController: Foo
init(viewController: TableViewController) {
self.viewController = viewController
}
}
class FooUtility1: FooImplementation {
// Methods
}
class FooUtility2: FooImplementation {
// Methods
}
class Foo: TableViewController {
var fooUtility1: FooUtility1
var fooUtility2: FooUtility2
override viewDidLoad() {
fooUtlity1 = FooUtility1(self)
fooUtlity2 = FooUtility2(self)
}
// Use of the methods...
}
Is there a better/universally defined way of creating and using these classes? And can these classes be combined into one Utility class that has access to all of the methods FooUtility1 and FooUtility2 provide?
Thanks!
I don't consider adding utility classes a good design pattern, for at least the following reasons:
they can change the internal status of the view controller
you have to "upgrade" member properties to internal or public when they are private by nature
Of course I don't know what kind of behaviors you want to move from view controllers to the utility classes - my advice is to use one or more of the following:
create view controller extensions
create your own set of base view controllers, inherited from UIViewController, to be used as super classes for your final view controllers
move some logic to external classes, but use the delegation pattern to interact
The second case is one I frequently use, and the 3rd is one I've applied to my latest project, using better separation of concerns by implementing for each view to be displayed:
a view controller, responsible of managing (but not displaying) the view, and handling events received from its view(s)
a data source, responsible of providing the data to be displayed in the view, along with methods to add/delete/update if needed
a (hierarchy of) view, implemented in a separate class in its own xib file.
It makes development a little more complicated, but in the end I have a light view controller, and a view that is responsible of displaying data, handling events and forwarding them to the view controller.
Note that this is not the solution, just one possible solution. There are several variables to take into account, for sure what you want to move from the view controller, and I think also personal preference.
On my first project trying out Caliburn.Micro, I like a lot of the things :-)
One thing I miss (or havn't discovered yet) is how to separate the viewmodel and a command.
CM doesn't support ICommand, as it's way of doing things is superior. I'm sure it's true, so I would love a small push in the right direction to achieve this or perhaps discover a better way.
As I understand you have to put the "Execute" method and "CanExecute" property directly in the viewmodel, named to match the control in the view, to get the magic to work.
I would like to put the "Execute" and "CanExecute" in a different object that is property on the viewmodel and then CM would automatically bind to that object, using the control name and property names as usually.
Repost from the forum on Caliburn Micro, I didn't get any answers so I'm trying my luck here.
You should try to avoid invalidating the Law of Demeter. Therefore, on your view model you can have an execute method, and a CanExecute property (usually calculated), and these can call into the containing model where appropriate, e.g:
public void Save
{
// .. save logic
}
public bool CanSave
{
get
{
return this.model.CanSave ... and other logic etc.
}
}
You must remember to notify a change in the calculated property when the can save state changes, e.g:
public void CodeThatGetsRunWhenAPropertyOfTheModelChanges()
{
this.NotifyOfPropertyChanged(() => this.CanSave);
}
If you have e.g. a Button on your view with x:Name="Save", then Caliburn.Micro will automatically invoke your Save verb on the view model when the button is clicked, and will automatically enable and disable the button when the CanSave property value changes.
To avoid fat ViewModels you also need to avoid fat Views. Caliburn.Micro allows you to compose Views/ViewModels as described in Screens, Conductors and Composition.
The short version is, you can include a "DetailView" and "DetailViewModel" pair in a "MasterView"/"MasterViewModel" shell by defining a DetailViewModel-typed property in MasterViewModel and adding a ContentControl named after it in MasterView. Binding and actions work as usual, so you avoid both fat models/views and routing of commands.
Another option is to bind a MasterView element to a DetailViewModel property or action, by prepending the detail's property to the target's name. I can't find the specific URL yet, so the example is from memory.
Assuming you have the following classes:
public class MasterViewModel:Screen
{
public property DetailViewModel MyDetails{get;set;}
}
and
public class DetailViewModel:Screen
{
public property string SomeText{get;set;}
public void DoTheBoogie(){}
}
You can add a control in you MasterView named 'MyDetails_SomeText' to bind to the DetailViewModel.SomeText. You can also bind to DoTheBoogie the same way.
I prefer to create a separate View though, named DetailView and add a ContentControl named "MyDetails" in MasterView. This results in a cleaner and more modular design
i want to be able to get data from my controllers to be made accessible from all views or layouts.. so that i dont have to assign a variable to each controller everytime..
in my case, in my layout.phtml, theres a list of categories direct from the db, for now, i am assigning this to every controller:
class productsController extends Zend_Controller_Action {
public function init() {
Zend_Layout::getMvcInstance()->assign('categories',$dbArrayCategories));
}
}
but i dont want to repeat it every time for each controller..
This sounds like a case where I would use a ViewHelper: http://framework.zend.com/manual/en/zend.view.helpers.html. This will let you use it in any view or layout. I typically pass a model into my helper, but you can definitely have it load one up by default.
You might extend Zend_Controller_Action with you own base class and assign the values directly in the constructor or init method.