I'm trying to learn how delegates work and wrap my head around the concept. I'm finding I get some of the ideas. I understand you use it to pass data from one view controller to another, however wouldn't it work the same if I just sent data from a segue and every time the 1st view controller would appear, it would use that data?
So for example I have 2 view controllers.
1 is homeViewController and
2 is editViewController.
I have a variable titled "addressOfHome" which is a string in homeViewController(1).
In homeViewController under the method "viewDidAppear"
I also set the addressLabel = addressOfHome.
Then I just pass the data from editViewController(2) to homeViewController(1)
when the segue's destination vc is homeViewController ?
I'm terrible at explaining things so I apologize for that, but I gave it my best shot. Thanks for your time!
Delegates are mainly used to "trigger action" on an object from another one.
An object delegates a way to handle something to someone else, for example when you click on an UIAlertView button, if its delegate is set on a viewController, alertView:clickedButtonAtIndex will be executed on the VC, which can so react as it want
I'm terrible at explaining things
Haha, yes, you are !
A delegate isn't for that - a delegate is a way to over-ride the default behaviour of some feature(s) of a class, without creating your own sub-class. See this post : How does a delegate work in objective-C?
Are you trying to understand how delegates work (in which case, I don't think your example is one that requires a delegate) or are you trying to implement the functionality you describe, and think that a delegate is the way to do it? (I think you actually want a data source).
I've been reading about Clean Architecture from Robert Martin and more specifically about VIPER.
Then I ran into this article/post Brigade’s Experience Using an MVC Alternative which describes pretty much what I'm currently doing.
After actually trying to implement VIPER on a new iOS project, I've ran into some questions:
Is it ok for the presenter to query information in the view or should the "information passing" always start from the view?
For example, if the view triggered some action in the presenter, but then, depending on the parameters passed through that action, the presenter might need more information.
What I mean is: the user tapped “doneWithState:”, if state == “something”, get information from the view to create an entity, if state == “something else”, animate something in the view. How should I handle this kind of scenario?
Lets say a "module" (group of VIPER components) decide to present another module modally. Who should be responsible for deciding if the second module will be presented modally, the first module's wireframe or the second module's wireframe?
Also, lets say the second module's view is pushed into a navigation controller, how should the "back" action be handled? Should I manually set a "back" button with an action in the second module's view controller, that calls the presenter, that calls the second module's wireframe that dismiss and tells the first module's wireframe that it was dismissed so that the first module's view controller might want to display something?
Should the different modules talk only through the wireframe or also via delegates between presenters? For example if the app navigated to a different module, but after that the user pressed "cancel" or "save" and that choice needs to go back and change something in the first module (maybe display an animation that it was saved or remove something).
Lets say a pin was selected on a map, than the PinEditViewController is displayed. When going back, the selected pin's color might need to change depending on use actions on the PinEditViewController. Who should keep the state of the current selected pin, the MapViewController, the MapPresenter or the MapWireframe in order for me to know, when going back, which pin should change color?
1. May the Presenter query information from the view
To answer this to your satisfaction, we need more details about the particular case. Why can't the view provide more context information directly upon callback?
I suggest you pass the Presenter a Command object so the Presenter doesn't have to know what to do in which case. The Presenter can execute the object's method, passing in some information on its own if needed, without knowing anything about the view's state (and thus introducing high coupling to it).
View is in a state you call x (opposed to y and z). It knows about its state anyway.
User finishes the action. View informs its delegate (Presenter) about being finished. Because it is so involved, it constructs a Data Transfer Object to hold all usual information. One of this DTO's attributes is a id<FollowUpCommand> followUpCommand. View creates a XFollowUpCommand (opposed to YFollowUpCommand and ZFollowUpCommand) and sets its parameters accordingly, then putting it into the DTO.
Presenter receives the method call. It does something with the data no matter what concrete FollowUpCommand is there. Then it executes the protocol's only method, followUpCommand.followUp. The concrete implementation will know what to do.
If you have to do a switch-case/if-else on some property, most of the time it'd help to model the options as objects inheriting from a common protocol and pass the objects instead of the state.
2. Modal Module
Should the presenting module or the presented module decide if it's modal? -- The presented module (the second one) should decide as long as it's designed to be used modally only. Put knowledge about a thing in the thing itself. If its presentation mode depends on the context, well, then the module itself can't decide.
The second module's wireframe will receive message like this:
[secondWireframe presentYourStuffIn:self.viewController]
The parameter is the object for which presentation should take place. You may pass along a asModal parameter, too, if the module is designed to be used in both ways. If there's only one way to do it, put this information into the affected module (the one presented) itself.
It will then do something like:
- (void)presentYourStuffIn:(UIViewController)viewController {
// set up module2ViewController
[self.presenter configureUserInterfaceForPresentation:module2ViewController];
// Assuming the modal transition is set up in your Storyboard
[viewController presentViewController:module2ViewController animated:YES completion:nil];
self.presentingViewController = viewController;
}
If you use Storyboard Segues, you'll have to do things a bit differently.
3. Navigation hierarchy
Also, lets say the second module's view is pushed into a navigation controller, how should the "back" action be handled?
If you go "all VIPER", yes, you have to get from the view to its wireframe and route to another wireframe.
To pass data back from the presented module ("Second") to the presenting module ("First"), add SecondDelegate and implement it in FirstPresenter. Before the presented module pops, it sends a message to SecondDelegate to notify about the outcome.
"Don't fight the framework", though. Maybe you can leverage some of the navigation controller niceties by sacrificing VIPER pure-ness. Segues are a step into the direction of a routing mechanism already. Look at VTDAddWireframe for UIViewControllerTransitioningDelegate methods in a wireframe which introduce custom animations. Maybe this is of help:
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed
{
return [[VTDAddDismissalTransition alloc] init];
}
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented
presentingController:(UIViewController *)presenting
sourceController:(UIViewController *)source
{
return [[VTDAddPresentationTransition alloc] init];
}
I first thought that you'd need to keep a stack of wireframes similar to the navigation stack, and that all "active" module's wireframes are linked to one another. But this isn't the case. The wireframes manage the module's contents, but the navigation stack is the only stack in place representing which view controller is visible.
4. Message flows
Should the different modules talk only through the wireframe or also via delegates between presenters?
If you directly send another module B's object a message from Presenter A, what should happen then?
Since the receiver's view is not visible, an animation cannot start, for example. The Presenter still has to wait for the Wireframe/Router. So it has to enqueue the animation until it becomes active again. This makes the Presenter more stateful, which makes it harder to work with.
Architecture-wise, think about the role the modules play. In Ports/Adapters architecture, from which Clean Architecture burrows some concepts, the problem is more evident. As an analogy: a computer has many ports. The USB port cannot communicate with the LAN port. Every flow of information has to be routed through the core.
What's at the core of your app?
Do you have a Domain Model? Do you have a set of services which are queried from various modules? VIPER modules center around the view. The stuff modules share, like data access mechanisms, don't belong to a particular module. That's what you may call the core. There, you should perform data changes. If another module becomes visible, it pulls in the changed data.
For mere animation purposes, though, let the router know what to do and issue a command to the Presenter depending on the module change.
In VIPER Todo sample code:
The "List" is the root view.
An "Add" view is presented on top of the list view.
ListPresenter implements AddModuleDelegate. If the "Add" module is finished, ListPresenter will know, not its wireframe because the view is already in the navigation stack.
5. Keeping state
Who should keep the state of the current selected pin, the MapViewController, the MapPresenter or the MapWireframe in order for me to know, when going back, which pin should change color?
None. Avoid statefulness in your view module services to reduce cost of maintaining your code. Instead, try to figure out whether you could pass a representation of the pin changes around during changes.
Try to reach for the Entities to obtain state (through Presenter and Interactor and whatnot).
This doesn't mean that you create a Pin object in your view layer, pass it from view controller to view controller, change its properties, and then send it back to reflect changes. Would a NSDictionary with serialized changes do? You can put the new color in there and send it from the PinEditViewController back to its Presenter which issues a change in the MapViewController.
Now I cheated: MapViewController needs to have state. It needs to know all pins. Then I suggested you pass a change dictionary around so MapViewController knows what to do.
But how do you identify the affected pin?
Every pin might have its own ID. Maybe this ID is just its location on the map. Maybe it's its index in a pin array. You need some kind of identifier in any case. Or you create an identifiable wrapper object which holds on to a pin itself for the duration of the operation. (That sounds too ridiculous for the purpose of changing the color, though.)
Sending Events to Change State
VIPER is very Service-based. There are lots of mostly stateless objects tied together to pass messages along and transform data. In the post by Brigade Engineering, a data-centric approach is shown, too.
Entities are in a rather thin layer. On the opposite of the spectrum I have in mind lies a Domain Model. This pattern isn't necessary for every app. Modeling the core of your app in a similar fashion may be beneficial to answer some of your questions, though.
As opposed to Entities as data containers into which everyone might reach through "data managers", a Domain protects its Entities. A Domain will inform about changes proactively, too. (Through NSNotificationCenter, for starters. Less so through command-like direct message calls.)
Now this might be suitable for your Pin case, too:
PinEditViewController changes the pin color. This is a change in a UI component.
The UI component change corresponds to a change in your underlying model. You perform the changes through the VIPER module stack. (Do you persist the colors? If not, the Pin Entity is always short-lived, but it's still an Entity because its identity matters, not just its values.)
The corresponding Pin has changed color and publishes a notification through NSNotificationCenter.
By happenstance (that is, Pin doesn't know), some Interactor subscribes to these notifications and changes its view's appearance.
Although this might work for your case, too, I think tying the edit
This answer may be a bit unrelated, but I'm putting it here for reference. The site Clean Swift is an excellent implementation of Uncle Bob's "Clean Architecture" in swift. The owner calls it VIP (it still contains the "Entities" and the Router/wireframe though).
The site gives you XCode templates. So let's say you want to create a new scene (he calls a VIPER modules, "scenes"), All you do is File->new->sceneTemplate.
This template creates a batch of 7 files containing all the headache of the boilerplate code for your project. It also configures them so that they work out of the box. The site gives a pretty thorough explanation of how every thing fits together.
With all the boiler plate code out of the way, finding solutions the questions you asked above is a bit easier. Also, the templates allow for consistency across the board.
EDIT -> In regards to the comments below, here's an explanation as to why I support this approach -> http://stringerstheory.net/the-clean-er-architecture-for-ios-apps/
Also this one -> The Good, the bad, and the Ugly about VIPER in iOS
Most of your questions are answered on this post: https://www.ckl.io/blog/best-practices-viper-architecture (sample project included). I suggest you pay special attention to the tips for Modules initialization/presentation: it's up to the source Router to do it.
Regarding back buttons, you can use delegates to trigger this message to the desired module. This is how I do it and it works great (even after you insert push notifications).
And yes, modules can definitely talk to each other by using delegates as well. It's a must for more complex projects.
I'm rather new to objective C and at the moment I'm trying to create one small project.
The task I want to accomplish is the following:
I've got the UIViewController for the screen of the game I'm creating. It has an UIImageView and a UITextView on it. What it does so far is that the latter one is moving towards the former one. And when their frames intersect (CGRectIntersectsRect) some actions happen.
What I want to achieve next is to create a specific class for UITextviews, so that there will be many of them created on the screen of UIViewController (I think array should be used here). And next I want every of them to be checking themselves, if they have an intersection with the UIImageView - than (again) something happens.
I've tried several ways like creating a mutable array, but every time I've some errors connected with variables of the original ViewController used inside of the new class (Hit).
The code I use for the one existing UITextView, that is created inside of UIViewController, is the following:
-(void)Moving{
HitR.center = CGPointMake(HitR.center.x+HitRX, HitR.center.y+HitRY);
if (CGRectIntersectsRect(HitR.frame, Finish.frame)) {
/*some actions here*/
}
}
etc
Can you help me to create these array of UItextFields, using their own class, tell them what to do with the help of properties like UIimageview.frame from the ViewController and then to place them on the screen.
P.S. I've read numerous articles about how to transfer variables from one class to another, but still failed to accomplish my aim.
I have created a custom class for my UIBarButtonItem (refreshIndicator.m). This button will be on many different view controllers, all push-segued from my MainViewController/NavigationController.
Instead of dragging an outlet onto every single ViewController.m file for iPhone storyboard THEN iPad storyboard (ugh, still targeting iOS7), I want to know if there is a way to complete my task simply within my UIBarButtonItem custom class. I've looked around everywhere but I haven't quite found an answer to this,
All I need to do is check which UIViewController is present, check the last time the page was refreshed, and then based on that time, set an image for the UIBarButtonItem. (I've got this part figured out though, unless someone has a better suggestion). How can I check for the current UIViewController within a custom button class? Is this possible?
Does it need to know which view controller its on so it can tell that vc it was pressed? If that's the case, then use your button's inherited target and action properties. On every vc that contains an instance of the button, in view did load:
self.myRefreshIndicator.target = self;
self.myRefreshIndicator.action = #selector(myRefreshIndicatorTapped:);
- (void)myRefreshIndicatorTapped:(id)sender {
// do whatever
}
More generally, its better to have knowledge about the model flow to the views from the vc, and knowledge of user actions flow from the views. Under that principal, your custom button could have a method like:
- (void)timeIntervalSinceLastRefresh:(NSTimeInterval)seconds {
// change how I look based on how many seconds are passed
}
And your vcs:
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:self.lastRefreshDate];
[self.myRefreshIndicator timeIntervalSinceLastRefresh:interval];
If you really must go from a subview to a view controller, you could follow the responder chain as suggested in a few of the answers here (but I would go to great lengths to avoid this sort of thing).
It is possible to achieve this, but the solution is everything but elegant. It is one way of getting around the basic principles of iOS and is strongly discouraged.
One of the ways is to walk through the responder chain, posted by Phil M.
Another way is to look through all subviews of view controllers until you find the button.
Both ways are considered a bad practice and should be avoided.
For your particular case, I would rethink the structure of having a separate instance of the bar button. For example, you could rework it into a single UIButton instance that gets displayed over every view controller and it can also act as a singleton.
I'm currently trying to build my own Custom ContainerViewController.
I'm quite familiar with the iOS ViewController containment API (introduced in iOS 5) and the new iOS7 ViewController Transition API.
While implementing my container, i tried to utilize the same patterns UINavigationController and UITabBarController are using.
My Container is working well so far and using animated and interactive transitions properly.
The Problem is, i packed a huge amount of the logic into my UIViewController container subclass. It is conforming to <UIViewControllerContextTransitioning> and uses iVars to store all the values returned by that protocol's methods.
The animation and interaction logic is already separated in another class and third-parties are also able to provide their own transition using a delegate similar to UINavigationControllerDelegate and UITabBarControllerDelegate.
What I'm trying to do now is out-sourcing the UIViewControllerContextTransitioning to a separate class to create the same modularity Apple does for it's containerVCs.
Apple provides a UIViewControllerOneToOneTransitionContext (private API) for the id<UIViewControllerContextTransitioning> object handed to the UIViewControllerAnimatedTransitioning and UIViewControllerInteractiveTransitioning methods. So they are NOT using their UIViewController subclass for that. (That's what i do at the moment)
My current structure is in so far tempting to keep for me as when the transition logic calls [updateInteractiveTransition:], [completeTransition:], etc. on the context, these calls are made directly on my containerController which can then respond by updating other elements in it's view. (Like UINavigationController does when you call [updateInteractiveTransition:] and it's updating the content of the NavigationBar (cross-fade)).
Out-Sourcing the contexttransitioning logic in another class would mean:
Provide the viewControllers and frames, etc. which are hold in the stack of my container FROM the container TO the context object because the context needs to provide them to the transition logic.
Call transition-callbacks FROM the context object ON the container because the context object is the one receiving them from the transition logic.
As Apple uses this class-relationship, there must be some advantage about it, i guess.
Currently, i don't know if i should keep my implementation, or try to make it as modular as Apple-provided containers.
Also see this SO - Question where i asked the same thing. (More like an answer-question, sorry for that :/ )
While we're on the topic : Is it possible to make my container work with UIPercentDrivenInteractiveTransition ? The documentation says it cuts the animation executed by the transitionAnimator in keyframes and automagically "replays" the animated transition step by step, so i doubt it can be used with custom containers.
Thanks for your help !
Apple uses a lot of small classes conforming to certain protocols to hand over pieces of work. Divide and conquer. Have a look at for instance the way UITableView operates or collection view. They did split things into smallest chunks possible, and provided each one with some generic objects. These objects only conform to certain Protocols.
Do not force people to subclass.
Create protocols that classes fulfilling certain roles have to conform to.
Where you want to create ready to use objects that will perform certain actions - return id type of object, not a class object. That's the only way to keep things simple and flexible enough.
Apple does that even with NSObject, which is both a class and protocol.
When creating your own protocols, remember to make them conform to NSObject * protocol.
Your question is rather long, and does not ask any specific questions, so I hope this answers some of your concerns. If not, feel free to post one to response to this.