I have a fairly complex application at this point, and feel as though the way I am handling data is not up to scratch.
So I have started taking some steps towards making my app more MVC friendly.
The first of which, I have gone from having inline parser methods in all of my ViewControllers to creating a dedicated parser class.
Its not hard to call I just set up the class then call the initializer method I have made which I pass the data to for my request.. everything in my object class works sweet I get a whole bunch of return data from the server that I am parsing.. but then this is where I get abit lost.
How do I get that data back to the ViewController that called it? I have worked a little with protocols and delegates.. but I dont know how that would fit into this.
Here is an graphical example of what I am trying to achieve.
So as above View controller calls the initalization method of the object class which connects to the DB downloads the data, and then parses that data. The issue I am having is how do I then get that data to ViewController2..
what is the most appropriate and future proof way of doing this?
A custom -init method does wonders. For instance, I needed to instantiate and push a picker preloaded with the array from the previous screen, so I defined -(id)initWithArray:(NSArray*)array in the second view, then just called secondView = [[SecondView alloc]initWithArray:_population]; then pushed it. Remember to get ownership of any object you pass before it is deallocated and destroyed!
If you want to broadcast data from your object to all view controllers the good way to do this will be by notifications (NSNotificationCenter). You could also write a methods with completion blocks inside your parser object.
Try to send a local notification using NSNotificationCenter. Register your ViewController2 as a listener, then upon receiving the notification, call your data model (singleton!?) for the data.
Related
So I'm using multiple delegates to pass trough data, but I don't know if it's the right way. I only want to maintain 1 main object to be sure that if a user exists/closes the app the edit data is saved when not in the VC1. By using the delegates now I'm sure the data is in the main object and all is well. Could you guys send me in the right direction and tell me if this is the way to go? Thanks in advance!
VC1:
Main object, holds all data that needs to be saved
Delegate for VC2
VC2:
Specific object overview from VC1
Delegate for VC3
Delegate function called -> PassDataToVC1(editsForSpecificObject)
VC3:
Edit's data from specific object. -> Gives
Delegate function called -> PassDataToVC2(edits)
Maybe even a 4th VC depending what I'm going to do.
What you're doing is basically correct for the architecture you have chosen:
If you have a rule that only VC1 knows the full data and can save it, then you need to pass changes in the data back to VC1.
If you have a rule that the way to pass the data back to VC1 is to use a protocol-and-delegate architecture, then you have to make VC1 the delegate for your protocol(s). There is nothing wrong with a single object (your VC1) being extended to adopt multiple protocols; that, indeed, is a standard Swift pattern.
However, I would argue that the reason this feels ugly to you is that those are not very good rules. I'll address them in reverse order:
Why delegation? In modern Swift, there are cleaner ways to pass data around. Modern app architectures are typically reactive, meaning that a handler of data is a publisher of the changes in that data, and the central store of the data subscribes to those publishers. Thus the data store can hear directly of any changes without the view controllers having to send those changes to anyone in particular.
Why a view controller? This is arguably the weakest point in your architecture. What business is it of a view controller to know anything about the data store and the mechanism for saving it? You should have a separate data store object retained by some securely persistent object such as the app delegate. This object stores and gatekeeps the data, and knows (or has a service helper who knows) how to persist it. You can use dependency injection to hand a reference to this object to every view controller — which also has the added benefit of making your code eminently testable. Even better, if you accompany this idea with the use of reactiveness that I outlined in the previous paragraph, you will have a clean "touch-free" architecture that just works, where every object does its own job and no other.
I am developing one navigation based application. All data required for each screen are getting downladed from webserver. I am starting downloading in viewDidLoad method. ALl downloadinh is happening asynchroniously and respective viewcontroller will receive data through delegate pattern. Now my question is in case new viewcontroller is getting pushed on navigation stack or current view controller is getting popped off so fast before data will get received, how we will handle this situation? We do not want to block UI so user can move back or forward. I used notification mechanism to detect particular view controller (one who receive data ) is alive or not , but it seems like not a concrete solution. So basically I want to detect receiver is appropriate for receiving downloaded data before I make a call to its delegate method.
Any pointer related to it is highly appreciable.
Thanks!
Nilesh
I think the dataSource pattern is more appropriate.
1) Create a datasource (singleton or attached in your app delegate)
2) Implement a method dataWithPredicate: (or just data)
3) Notify your viewController (with NSNotificationCenter) when a data is updated
4) Reload data from the controller (with dataWithPredicate: call)
Another way is to use core data for that. CoreData generate all the notification and do the job for you.
I have had about 6 hours trying to work out custom application delegates. even following tutorials i end up with errors!
I need a simple way of allowing one object to talk to another.
I have a root view. then another view which then pushes onto the stack with a list of options. then another view showing the relevant options based on the previous selection.
So basically 3 views, and i need view 3 to pass data back to view 1 when i popBackToRootViewController.... This is becoming a huge headache, for something that in theory should be so simple. I have previously just thrown data into nsuserdefaults but using protocols in the way apple suggest to do it.
Please can someone help me understand :)
There a different ways to solve that problem. First of all, you could pass the first View over and over to the View you are making changes on and then call a method of view 1. I won't recommend that.
Another, much easier way is to use Notifications. Just register your first View in the notification center [[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(somethingChanged) name:#"aStringWichIsUniqeForCallingSomethingChanged" object:nil];. You have to provide and implement a callback method (somethingChanged in my case). In your subwiew where the things happen, you have to post a notification by doing [[NSNotificationCenter defaultCenter] postNotificationName:#"aStringWichIsUniqeForCallingSomethingChanged" object:nil];. And don't forget to remove the view from the notificationcenter if they are not needed anymore!
[[NSNotificationCenter defaultCenter] removeObserver:self];
A third possibility is to use a singelton (like the app delegate) which contains all views that should communicate. Simple make all views as ivars & properties for them in this singleton and implement in each of them methods which should be called if something changes. Then call [[singelton sharedInstance] view1] somethingChanged].
If i say View, i mean viewController, but i'm to lazy to write that. ;)
Hope, that helps!
Protocols and delegation formalize a concept which works even if you don't follow the formal rules: It's about declaring a way for objects to talk to each other about the same thing, especially in those cases where you either don't have or don't want control about one of the objects, or in cases where things get complex and you want everything nice and tidy so it's easier to reuse the code.
In those cases however where a rather small, well known set of information is to be passed back and forth between two (or more) well known objects which are unlikely to be reused, informality is quite ok.
This means you could:
provide the sending object with a property of the type of the receiving object
implement a method in the receiving object which will take the information to be sent as an argument
at some point, for example in your case when the root controller pushes the child which becomes the sending object, the receiving object will set itself as the value of the sending object
if the sending object has information to send, it uses the reference to the receiving object to send it a message calling the earlier mentioned method, passing the information as an argument
As I mentioned before, this makes sense for glue code. You shouldn't be doing it this way though, if:
you're working in a team and you're working on one object and a teammate is working on the other
it's obvious you may be able to use the same functionality in a future project. In this case, think about having an intermediate subclass between your original superclass and your app-specific subclass, one that encapsulates the core functionality and offers a formal protocol to interface with it
the exchange of information involves objects of different classes within the same app
the exchange of information itself is rather complex and one (or two) glue methods wouldn't cover it
I'm new to programming, iphone application programming in specific. After reading a bunch about MVC I decided to give it a try in a small application. As to my understanding, MVC works like this:
Model: data, manipulating data, retrieving data.
ViewController: formats data from the model (NSDate to specific style), etc.
View: the actual gui.
If this is indeed a correct formulation of basic MVC theory, my confusion lies in how data is passed between the model, VC, and view. Example: if I make calls to twitter and get the data in the model, how do I (correctly) pass this information to the VC for further work. I know that between the VC and View one mostly uses IBOutlets. The Model is my real problem.
In my last app I made an NSString variable in the app delegate so I could access that data from any class. However, I read that this is not the best approach when the app becomes complex because the delegate is in charge of starting, ending the app, not holding data.
I've read of delegation methods, singleton's, NSNotification (which I've used to call methods in other classes). The problem is that I don't really understand how to use these techniques to pass data from the model to other views.
Please let me know if my question is unclear.
If you think about reusability, the main components that can be reused again are your model objects and view objects. They can be moved to different apps and still used properly. Your view controller is what is really specific to your app and where most of the app logic lies.
So in your example, you could have a twitter object that stores information and tweets from a user perhaps. You would create that class with all its functions separately within its own .h and .m file. Then in your view controller, instantiate the twitter class with data that is retrieved and begin using it from within the view controller.
Your view controller is actually retrieving the data but your model object is the one maintaining the data. In this way, you can pass on the model data with your twitter object to other view controllers.
Control over the application resides in the controller, so it is the object that will retrieve or save persisted data, update views with that data, and handle various events. Consider it the glue between the model and the view!
For example, if you were to click on a button to open a new modal view, you'd handle that event in your view controller. In the method that responds to the clicked button, you will create or access the new view controller and present it using presentModalViewController:animated:. If that new view and controller needs data that your current controller has access to, you could set a property in the new controller to refer to the object.
I have setup and successfully logged in via xAuth using an extended class of MGTwitterEngine, my question is if I want to pass this to another view controller, how can I change the delegate class, as it is some sort of weak reference
#interface MGTwitterEngine : NSObject <MGTwitterParserDelegate> {
__weak NSObject <MGTwitterEngineDelegate> *_delegate;
Am I best wrap this up into a singleton class and pass around that way, seems overkill to login in each time, or have I missed a painstakingly obvious way of sharing this object around
At the moment I have added a setDelegate method to the MGTwitterEngine but feel as though I am fighting the framework unnecessarily
If you're sharing the engine across multiple objects then you would want to have some other object/singleton wrap the engine and act as its sole delegate. If you've done database programming then think of it like a database connection -- you probably wouldn't have each view controller create its own database connection. Instead you'd create some sort of data manager object that is shared by the views and possibly abstracts away some of the DB internals.
If different view controllers handle different tasks -- like login, looking up users, querying messages, etc. then the delegate methods in your wrapper should be able to pass the responses along to the appropriate view controller.
If you have different view controllers calling the same methods (and if so, why?), you could still route responses back to the corresponding view controllers. As the MGTwitterEngine docs say, "Each Twitter API method returns an NSString which is a unique identifier for that connection." You would just need to pass an object (your view controller) or a block as an extra parameter to each of your wrapped methods. You can cache the twitter id string and this object/block in a mutable dictionary when your wrapper sends the response, then look up the connection id in the cache when it's time to handle the response.
actually, you can.
The delegate, is nothing but a variable in the MGTwitterEngine. Just add a instance of it in the next view controller adding the proper header and inplementation calls.
after instatiating the new view controller set:
nextViewController._mgTwitterEngine = self.mgTwitterEngine;
nextViewController.mgTwitterEngine.delegate=nextViewController;
then call the nextViewController.
Do not forget to set the delegate back to the original view controller when you return to it (either on viewDidAppear or viewWillAppear)
Hope that helps...
Best Of luck!
Use NSNotifications in the delegate.
Make the view controller where you wish the delegate to be add an observer. Have the delegate method for MGTwitterEngine post the notification.