Imagine there is a method in my MVC Controller who can be called multiple time during different time of is life.
Is there a way to retrieve, and print out enventually, in wich state is this Controller ?
It's maybe a short and/or dumb question, but with this indication it'll be easier to know if this method is called at a wrong or good time.
I wrote a blog post about exactly this: managing Application LifeCycle as you move through an App.
I'd suggest you subclass UIViewController with this LifeCycleViewController, and then for every VC in the App subclass the LifeCycleViewController. That way as you move around, in the logs you'll get:
'RootView willAppear'
'RootView didLoad'
etc.
Related
I've being working for a bit now with MVVM along with Swift. The principle is very simple:
ViewController is responsible for the View;
ViewModel is responsible for the Model;
ViewController owns the View;
ViewController owns the ViewModel;
ViewModel own the Model;
period.
That's clear to me. But there are some questions I still have about it (they might sound stupid, but it's important to be as clear to newbies as the rules above):
Should ViewModel be responsible for the business logic? I mean, since ViewController don't own models, it feels right to place the biz logic in ViewModel;
Should ViewModel be a struct? This is a tricky one. I'm guessing ViewModel should also give an API to ViewController interact with data. Therefore, sometimes we need to use some escaping closures in order to fetch asynchronous data (e.g. HTTP calls). Structs can't hold it.
Should I hide non-outlets variables from ViewController? Sometimes we need a strong reference to some property in order to present views (e.g. keep the current page of an UIPageControl). Should ViewController hold this reference?
How can I fire ViewController updates from ViewModel? I do read about reactive programming, but my question is wider: Sometimes ViewModel needs ViewController to respond to some actions, which is the best way to do it? Should ViewModel keep specific callbacks to specific reactions ViewController can handle? I came across Srdan Rasic's post about "binding" properties and I got confused (perhaps its not related to this question at all).
I'll be glad if you guys can share your solutions. Thanks!
Your question is quite wide. Someone will certainly explain it more widely than me, or might have different opinions. But these are my observations:
1. Yes ViewModel should be the only component which handles business logic
2. I guess that you answered it yourself, it should be a class. I do not have any reason for why should it be struct. But if it fits your needs who am I to say.
3. Depends on the use. If you use it for purpose of a view, then it is okay to have it here. There also exists a concept of having separate ViewModels for smaller parts, unfortunately, do not know the name. I mean you have a main ViewModel for a whole view and subViewModels for subview. So you will not end up having a big bunch of a code in ViewModel. Also sometimes it is acceptable technical debt (hope that no on will kill me for saying that)
4. It goes like this. You will press the button, you will call the method in your ViewModel called buttonPressed(or triggers an event). Then your ViewModel will do its job, probably obtain a new data and sets the view for that. From what I've seen you might do it with having a weak reference to your View in your ViewModel, or bind reactive properties in your View. The second option will leave you without the need of having View in your ViewModel, but you will have to to register observer for every view setting property from ViewModel.
So in my app I have the following situation:
BackendCommunicatingClass -> (owned by) -> ModelClass -> (owned by) -> HomescreenViewController
HomescreenViewController is a delegate for ModelClass.
ModelClass is a delegate for BackendCommunicatingClass.
Also on when the app launches for the first time, I have this:
WelcomeViewController -> (owned by) -> HomescreenViewController
HomescreenViewController is delegate for WelcomeViewController.
When the user types a username and password in the WelcomeViewController, this information needs to get all the way to BackendCommunicatingClass, and then all the way back to WelcomeViewController to display error if needed. Right now I have implemented this by passing information to each class in the communication chain, until it gets to BackendCommunicatingClass. The result is a lot of duplication of protocol methods and I feel like I'm doing it wrong.
What do you think?
Well I understand it is not the clearest solution, but without seing the code, and the purpose of your program, this what I suggest.
Implement Key Value Observing (KVO) in Back End view controller, observing change in the Home View Controller. As soon as Back end controller detect change in the text field, trough a dedicated variable in Home View controller, it fires all the operation it has to do.
When back end finish, it sends a NSNotification with the result of the operation. Home view controller which you have made listening to such custom notification, react to that and display error message or other staff.
It may sounds complicated, but KVO and notification are easy to implement, and there are plenty of docs and tutorial on the net.
If there is a clear 1:1 mapping of what those delegate protocols provide AND the delegate does not deal in UI stuff that nothing except the directly owning view controller should be concerned with, you could pass the delegate along to the end of the chain and set it directly as a delegate. This is what delegates are for - being able to allow an otherwise unconcerned object to communicate with another object.
That said, depending on how strict your layering policy is, you may prefer to encapsulate the information at every step by having different delegates.
So I'm getting myself into a confusion over where my data's going and where it's stored in my application. It's not a specific question so hopefully someone can provide a generalised answer.
I need to pass some data around between a few UIViewController instances, and I'm currently doing that with a singleton object called my dataManager. This class has one method, a class method, called + (LCDataManager *) sharedDataManager, and that method basically checks if whether the sharedDataManager already exists, if so, return it, if not, create it and set up its variables. This means that I can refer to that class anywhere I like, access and modify its variables anywhere I like, from across multiple classes.
First question: is this the correct / best / most appropriate means of passing data around like this? I'm hoping it obeys MVC, it feels like it does, and I hope I'm right.
Second question: what if I want to put an instance method in that class, and call it from within the class method? Let's say my sharedDataManager needs to call a method to grab some objects one of its variables (an array), and put them in another array, then send that back out again. I can't do that, can I? What's the way around that? If I make an instance of that class (rather than using the shared instance), I lose the ability to use that instance across multiple viewControllers.
I'm hideously confused, and it seems like it's not the problem I'm making it. Appreciate any guidance, and preferably not that "Read the Apple documentation" stuff – they write as if you already know what you're doing, and frankly I don't yet.
First question: is this the correct / best / most appropriate means of passing data around like this? I'm hoping it obeys MVC, it feels like it does, and I hope I'm right.
Your design is perfectly MVC compliant.
Second question: what if I want to put an instance method in that class, and call it from within the class method?
you can surely define an instance method and call it like this:
[[MyModelClass sharedModel] myInstanceMethod];
indeed, [MyModelClass sharedModel] will give you an instance of MyModelClass (which should be guaranted to be unique being it a singleton).
If you want to call the instance method from the sharedModel class method, you could also do that, because sharedModel owns a reference to your singleton, so it can send messages to it.
is this the correct / best / most appropriate means of passing data around like this?
There's nothing wrong with only having a single instance of LCDataManager, but using the Singleton pattern has potential problems. An alternative is to just initialize one LCDataManger and to pass it around to wherever it's needed.
what if I want to put an instance method in that class, and call it from within the class method?
The accessor + (LCDataManager *) sharedDataManager should only return the instance. I guess what you want is something like
+ (LCDataManager *)preparedDataManager {
LCDataManager *shared = [self sharedDataManager];
[shared doSomeInstanceMagic];
return shared;
}
- (void)doSomeInstanceMagic {
// magic!
// grab some objects one of its variables (an array),
// and put them in another array
}
Matthijs Hollemans has an excellent three-part tutorial on his blog about the correct way to make your view controllers talk to each other:
Part 1
Part 2
Part 3
there is no problem with this development architecture, and it is the must used (I think) in the iOS development. In the book IOS Programming: The Big Nerd Ranch Guide they call it Model View Controller Store.
Regarding your second question, yes, you can declare instance methods and call then from your sharedDataManager. What is not usual is creating other instances of a singleton class, but it is possible.
I have a few questions about code design. This might be long. I'll shorten it whereever possible.
Q1) Dependant or Independant?
Creating a class and adding required functionality so as to allow the object to change its own state vs state being changed by a controller (aka viewcontroller)
I find code examples are best when trying to communicate:
Note: I reduced some lines of code. Original code from http://www.techotopia.com/index.php/An_Overview_of_Objective-C_Object_Oriented_Programming.
Anyways if I had to set the Account balance for an account it is suggesting I do this:
#interface BankAccount: NSObject
{
double accountBalance;
long accountNumber;
}
-(double) getAccountBalance;
-(void) setAccountBalance: (double) x;
#end
// Implementation Section Starts Here
#implementation BankAccount
-(void) setAccountBalance: (double) x
{
accountBalance = x;
}
-(double) getAccountBalance
{
return accountBalance;
}
#end
//usage
BankAccount *account1 = [BankAccount alloc] init];
[account1 setAccountBalance: 1500.53];
----HOWEVER I believe I would have wrote it in a controller like this:------
#interface BankAccount: NSObject
{
double accountBalance;
long accountNumber;
}
import "BankAccount.h"
#interface MeViewController : UIViewController
-(void)setAccountBalance:(double)x toAccount:(BankAccount *)tempBankAcc;
#end
#implementation myViewController
-(void) setAccountBalance:(double)x toAccount:(BankAccount *)tempBankAcc
{
tempBankAcc.accountBalance = x;
}
//USAGE
BankAccount *account1 = [BankAccount alloc] init];
[self setAccountBalance(Account1,1500.53)]
#end
because I believe it is Me (meViewController) setting the AccountBalance, not the account itself as an account is just an account.
Is this a very bad idea? I can see with their example that the object can look after itself (independent) meaning changing its own state whereas my approach says that the BankAccount can only be modified through/with the controller (dependant)
???
Q2) What should/should not be in a controller?
I have also read somewhere that code written inside the controller should be only for:
Responding to user interaction & Updating the views
so does this means I should never do the following in the controllers:
READ or WRITE to and from NSUserDefaults. Since its a singleton, I thought it would be easier to write to it regardless of which controller is currently active? bad idea?
I understand that I should save data (includes NSUserDefaults) in applicationDidEnterBackground and in applicationWillTerminate so does that its a bad idea to save elsewhere (eg. in another controller).
Q3) Which design patterns do you most commonly use and which ones do you abuse wrongly?
Singletons:
My understanding is that [UIApplication sharedApplication],[NSNotification defaultCenter] and other singletons are accessible via all controllers, how about NSObject subclasses? or UIView subclasses?
And apparently you can use NSNotification to notify other controllers when the model has been updated.
Can someone tell me an example of when to use and how to use that?
Maybe when you import some data, that has different attributes, than was originally intended, then the observers could be notified of an upgraded data model, is that an example of when you would within your data model notify a controller?
Thats enough questions for now.
Sorry but I had to get them all out of my head:-)
Ben
First things first: don't use this
#interface BankAccount: NSObject
{
double accountBalance;
long accountNumber;
}
-(double) getAccountBalance;
-(void) setAccountBalance: (double) x;
#end
Here, the accountBalance ivar is public, while it should be private.
Instead, use a #property:
#interface BankAccount: NSObject
#property (assign, nonatomic) double accountBalance;
#end
That'll define a setter:
- (void)setAccountBalance:(double)accountBalance { ... }
and a getter:
- (double)accountBalance { ... }
and a private instance variable (ivar) named _accountBalance.
You can then, in your implementation, use:
#synthesize accountBalance;
which will automatically create the setter/getter like this:
- (void)setAccountBalance:(double)accountBalance {
_accountBalance = accountBalance;
}
- (double)accountBalance {
return _accountBalance;
}
Q1
If you take away all the business logic from the object itself, it's nothing more than a shallow container object. Further more, you need to replicate that logic in every controller you use. Business logic goes into business objects.
To your concrete example, the method of the controller does nothing but delegates the call down to the very object itself (infact, calling the same method if you use properties here). So you gained nothing at all. It may be fine to have that method in the controller, if the controller does more than just calling down on the object, maybe update some more data. One of the good hints here is that the controller does not use any of its own instance variables. It could easily be a class method. It's a code smell.
Q2
Basically, you have three choices for accessing NSUserDefaults: application level, view controller level, or view level.
Worst case is view level - a view should work in any context and should be configurable any way you like, and it certainly should not depend on some magic outside things. This would make reusability (not only for other apps, but also within the same app) a pain.
Accessing the defaults on the view controller level is often ok, especially if they take some singleton role. I.e. if you only ever have one playing screen and one setting screen, each of them might easily talk to the defaults. If there's the chance that you may have several instances of the same class differently configured, this gets a pain and bad smelling work arounds to "individualize" those.
This is where you want to place the access of the defaults outside of the view controllers, which is the most elegant and flexible approcach, but sometimes just not necessary.
Reusability may come earlier than expected, i.e. opening up a second text editor window (which might or might not show a different font), a second settings screen (i.e. a popover), a second playing screen for board games, etc.
Q3
I don't think Singletons are bad per se. They do come with a hefty price tag, though. They come convenient at early stages, just like global variables do.
They get very expensive, soon. There's no ownership, everything is shared, no chance to change a single bit without effecting the other users of that object. Reusability for objects depending on singletons is poor, as you always need those singletons as well. I tend to avoid them most of the time. And whenever I had one of them in my code, getting rid of them was a good decision.
As for the notifications: they are really designed for communicating on a system level. They shouldn't be abused for normal application logic and communication. It's a broadcast for system level events. If you use them as a substitute for object communication, this is a sure way to hell. This takes every logic out of the code, and there's no way build up responsible code.
Q1) Model-layer objects, especially ones that will be interacted with and mutated, should be responsible for their own internal representation as well as representing the knowledge of the rules of the interactions. For a bank account, I think both the approaches you present are wrong. The second in particular because it is actually taking even the responsibility of updating the state away from the account. But the first also because it only provides a setBalance method, which doesn't make sense in the real world. Whoever uses that account has to now handle all the logic of transfers, withdrawals, deposits, interest, and so on. Really, a bank account should have the methods deposit withdraw balance and so on, that way it can represent the rules and logic by which these interactions happen. In this case drawing from how this would work in real life can be helpful.
Q2) A lot of this depends on how your app is set up. A simple app's model layer may be just a plist or NSUserDefaults and some NSDictionary instances. In that case you might not want to have a view controller interact with it, but maybe a data controller object. But you can probably get away with having view controllers talk to that kind of model. When things get more complex though, you definitely need to separate concerns, and have controller objects closer to the data model or have more sophisticated models providing the rules of their interactions. Personally I'd avoid having all the view controllers loading NSUserDefaults, you could just make a single data controller class that could handle that and instantiate it as needed.
Q3) I see two questions here. Not sure what you mean by "accessible to all controllers". But NSNotification is incredibly useful when used right. Say you have 3 view controllers, all coordinating a different view of the bank account - one is a ledger, one is a pie chart, one is a budget calculator. When the app makes a request to refresh the bank account's information from the internet, when that request comes back it can notify all three of these view controllers at once and they can refresh their views accordingly. It's really used any time you have more than one object interested in knowing that something happened.
Hope this helps and let me know if you have any questions.
Read Stanford's lecture about MVC. I think you will find many answers there http://www.stanford.edu/class/cs193p/cgi-bin/drupal/node/205
I am making an object that goes to download stuff for all of my view controllers. The object is singleton instance and has a callback method with received data once the download is completed. It also has a delegate property so that it knows which object to call back to after the download is done.
There are multiple controllers that use this shared instance, and my question is how to call back to the correct view controller that requested the download.
My approach is to use delegation, but the problem is that since other view controllers are also its delegate, the download object could call back to every object and this will be hard to track.
I've worked on projects where people have attempted to use multiple delegates and it's basically a bad idea. The delegate pattern is about a 1 to 1 relationship between a class and it's delegate. Whilst it is possible to achieve some level of multiple delegation through switching the delegates in and out, it's more likely to lead to unpredictable behaviour and bugs.
My recommendation would be to change how you are thinking about this. You have two options as I see it:
Switch to an Observer pattern where you can register multiple observers which your main class can interact with. This is useful where your observers all implement the same protocol and where your main class wants to be aware of the observers and interaction with them.
Broadcast NSNotifications to indicate state changes and events. Here is a more decoupled approach because the main class does not need to know who is listening and does not directly interact with them. Other can start and stop being notified at their leisure. It also has the advantage that you do not need to create or implement a separate protocol. Instead you register the classes that need to know about changes with the NSNotificationCenter which in turns handles all the routing of notifications for you.
It actually sounds like the delegate pattern might not be the best approach here.
I would look into NSNotificationCenter instead.
The basic idea is that your singleton doing the net connection posts a notification (with something like postNotificationName:object:userInfo:) , saying that new data is available. Within this notification, you can pass a dictionary object (userInfo) that holds the data you've fetched, or info on what parts of your Model contain updated data.
Then, your other view controllers can register themselves to 'observe' these notifications by calling addObserver:selector:name:object:. Generally speaking, when a vc becomes visible I call addObserver, and removeObserver when it's being hidden or transitioned out.
Good luck!
Delegation doesn't seem like the right solution to this problem. How about requiring the requesting view controller to provide an object (its self) and a selector for you to call as a completion notification? Of course, you'll need a place to store that object and selector until the download completes. Hopefully you have (or could create) an object for this.
i recommend to use one of these ways
observer:
when use data that you want to inform other object are near to primitive ones.for example when you are using 'NSMutableArray' you can not inform the change in one of object by the standard implemented pattern at least you need to implement one for your self that is not reusable that much
Notification
when your interaction with destination object (those need to be inform) is in one-way.it means you don't need any acknowledge or other data back from them.
delegate
when there is one object to inform at each time step.
note:block use for success and fail is not a pattern to broadcast data its about to queue task when you don't know when they are finishing or failing like network operations
EDIT:
how to create notification | multi delegate issues and implementation
While I agree with most of the answers here, if you did actually want to achieve multiple delegates you could potentially declare an array of delegates and send messages to all delegates within that array. If your protocol has optional delegate methods you safely check using responds(to aSelector: Selector!) -> Bool before invoking (being mindful of memory management, as those delegates would be strongly referenced in the array). Again I do agree that multiple delegates is likely a bad architectural idea and using blocks or notification center would suit your needs better.
One approach, which works for me if you only have one other object to forward messages to is to create a forwardingDelegate This does not end up with issues of hard to debug ordering of delegates and it does not unnecessarily create a dependency on the other object. Keep in mind, if you have many objects then this might not be the best approach, it is mainly for one additional object but this could be extended to support an array of objects so long as there is one that receives the SDK and forwards it to the other objects [1]. Note that every method that is needed for the forwarded object needs to pass it along, even if it is not used by the forwarding object.
For example, if I need to forward the messages coming from the mapView delegate:
- (void)mapView:(MKMapView *)mapView regionDidChangeAnimated:(BOOL)animated
{
// handle this object here.
if ([self.forwardingDelegate respondsToSelector:#selector(mapView:regionDidChangeAnimated:)])
{
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
}
// or handle this object here.
}
[self.forwardingDelegate mapView:mapView regionDidChangeAnimated:animated];
The forwarding property would be declared like this.
#property (nonatomic) id<MKMapViewDelegate> forwardingDelegate;
And the other object would adopt the protocol as if it were receiving the original message.
[1] The array approach for multiple delegates may get tricky because then you don't have as much control over what order the delegates get called, as was mentioned in other posts.