Reputation: 4516
I've done some reading on here about passing data back from view controllers and I know that there are some definitely no-no's about this, but I wanted to inquire about a best practice for passing data in this manner and ask if what i'm doing below is ok?
I have 3 view controllers (classes ViewControllerA, B, and C) and when the user clicks a button (from either A, or B) it takes them to C using this:
let vc = new ViewControllerC()
self.presentViewController(vc, animated: true, completion: nil)
Passing data forward So 'self' above is either A, or B. My thought was if I wanted to send C some info, I could just make a property of C (such as a string or int, etc, etc) and assign it above just before I do a presentViewController. Is that right?
i.e. vc.propertyHere = "my value"
Passing Data Back if something happened in C that I'd like to send back to A or B, what is the best practice? To return back to A or B I know I can do this: self.dismissModalViewControllerAnimated(true)
Should I first instantiate A or B (maybe by their base type) and access a similar property for the information I'd like to pass back? For example if A and B both inherit from some class, I could make a property on that class and just access / set it from C. Is that the right move? Or is there a better approach? i.e.
callingViewController.myProperty = "my value i'm passing back"
Thanks!
Upvotes: 3
Views: 2752
Reputation: 17378
For downhill theres technically nothing wrong with your proposal of setting a property on the view controller
vc.propertyHere = "my value"
but theres a pattern called Dependancy Injection which provides a much cleaner conversation between the parent and the child.
So if your new view controller requires something to function you give it to the instance at init.
import Foundation
import UIKit
class ObjectTypeA {}
class ObjectTypeB {}
class FooVC : UIViewController {
var importantThing:ObjectTypeA!
var otherImportantThing:ObjectTypeB!
init(somethingINeed:ObjectTypeA, somethingElseINeed:ObjectTypeB) {
importantThing = somethingINeed
otherImportantThing = somethingElseINeed
super.init(nibName:nil,bundle:nil)
}
}
class BarVC : UIViewController {
func yo() {
let object1 = ObjectTypeA()
let object2 = ObjectTypeB()
let newVC = FooVC(somethingINeed: object1, somethingElseINeed: object2)
self.presentViewController(newVC, animated: true, completion: nil)
}
}
So keep doing what you are doing but look at other patterns in the future.
For passing data or events uphill a delegate pattern as described by others is best. That way there is no tight coupling between the parent and child. Any object which adopts the protocol can be the delegate.
e.g
class BlueSuedeShoes{}
protocol FunkyProtocol {
func danceLikeElvis(shoes:BlueSuedeShoes)
}
class LumpyVC:UIViewController {
var delegate:FunkyProtocol?
func somethingHappened() {
let myShoes = BlueSuedeShoes()
self.delegate?.danceLikeElvis(myShoes)
}
}
and a class which implements that protocol
class SmoothVC:UIViewController,FunkyProtocol {
func danceLikeElvis(shoes: BlueSuedeShoes) {
dontStepOn(shoes)
}
func dontStepOn(shoes:BlueSuedeShoes) {
}
}
Upvotes: 0
Reputation: 1558
You can use delegation pattern to achieve this. Here is an little example ,please see.
@protocol SecondViewControllerDelegate;
@interface SecondViewController;
SecondViewController : UIViewController
@property (nonatomic, assign) id<SecondViewControllerDelegate> delegate;
@property (nonatomic, retain) NSArray* someArray;
@end
@protocol SecondViewControllerDelegate
- (void)secondViewControllerDidFinish:(SecondViewController*)secondViewController;
@end
SecondViewController.m:
@implementation SecondViewController
@synthesize delegate;
@synthesize someArray;
- (void)dealloc
{
[someArray release];
[super dealloc];
}
- (void)someMethodCalledWhenUserIsDone
{
[delegate secondViewControllerDidFinish:self];
}
FirstViewController.h:
#import SecondViewController
@interface FirstViewController : UIViewController <SecondViewControllerDelegate>
{
...
}
@end
FirstViewController.m:
@implementation FirstViewController
- (void)secondViewControllerDidFinish:(SecondViewController*)secondViewController
{
NSArray* someArray = secondViewController.someArray
// Do something with the array
}
@end
Upvotes: 0
Reputation: 1885
Passing Data forward - Your implementation is good.
Passing Data Back -
Dont initiate A and B again, its a common mistake I see with new developers. A or B already exists, you came to this new controller from A/B and you just want to pass a value back to that class.
The best practice to use here is delegate design pattern.
Steps:
Create a protocol declaring the a method to call in A/B.
Implement a property in C named delegate.
Before presenting the view C, assign the delegate.
Whenever you want to pass any info to A or B call the delegate method.
Implementing delegate is explained in another SO answer here : How do I create delegates in Objective-C?
Upvotes: 1