How to pass data to a programmatically created child view controller - ios

In my app, I have created a child view controller that I have instantiated with a storyboard ID. I then programmatically add this child view to a UIScrollView which is why I can't simply create a container view in the storyboard. Heres what I need to still do: I need to pass data to the child VC. I know how to pass data while using a segue to a VC, but how would I perform this operation in this case?

The controller that you're adding the child to has a childViewControllers property that contains any children that controller has. If you only have one child, then you can reference it from the parent with,
SomeClass *child = self.childViewControllers[0];
child.someProperty = self.propertyIWantToPass;

Consider you want to send string data to ViewController2,ViewController3 from ViewController1.
Make property of the string variable in ViewController2 and ViewController3.
#property(nonatomic,strong) NSString *str;
And while pushing the ViewController2 and ViewController3:
ViewController2 *viewController = [ViewController2 alloc]init];
viewController2.str = #"Some text";
[self.navigationController pushViewController:viewController2 animated:YES];
And you have the data send from ViewController1 in ViewController2.

What about making a final destination for the data you want to pass in the child.
#interface ChildVC : UIViewController {
#property (nonatomic) id myPrivateData;
}
- (id)initWithData:(id)data;
#end
Then passing in the data with the -initWithData: when you instantiate.
ParentVC *vc = [[ParentVC alloc] init];
vc.dataIWantToPass = ...;
ChildVC *child = [[ChildVC alloc] initWithData:vc.dataIWantToPass];

It's been a while since I've done iOS,
After looking at Apple's documentation I'm pretty sure you can't add a ViewController to UIScrollView. You need to give it something that inherits UIView. You could subclass your UIView and give it properties or a method to pass data into before giving it UIScrollView.
UIScrollView inherits from UIView so it has the property UIScrollView.subviews which can be used to access the VIew you passed into it, if the reference is no longer available.
If you're only manipulating a UIViewController or one of it's subclasses then you can access the subview it manages through its property UIViewController.View

Related

ios Delegate Objective-c data sending from 2nd view controller to 1st view controller

I have 2 view controllers . First one is UIview controller and second one is table view controller.
I want to send data 2nd (table view controller) to first(uiview Controller) after the selection of rows of 2nd view controller.
For this i have written a delegate protocol.
But my delegate protocol is not working...
I figured out the problem.The object of second view controller that i am creating.
address = [[second_viewcontroller alloc] init];
address.delegate = self;
is different from self of second_viewcontroller view controller page.
How to make this two same.
self = [[second_viewcontroller alloc] init];
your problem my delegate protocol is not working... I figured out the problem.The object of second view controller that I am creating. address=[[second_viewcontroller alloc]init]; address.delegate=self; is different from self of second_viewcontroller view controller page.
It's clear say that way you create the second_viewcontroller object is not right.
You have to create the object from ViewController storyboard identifier.
First give the Storyboard ID to ViewController from Storyboard.Follow this step to Giving the Storyboard ID.
Select the particular ViewController in Storyboard.
Go to IdentityInspector.
Under IdentityInspector, There is identity section and add the Storyboard ID In "Storyboard ID" Field.
Syntax For Creating a ViewController Object.
Second_viewController *aVC = [self.storyboard instantiateViewControllerWithIdentifier:#"Second_viewController"];
aVC.delegate = self;
I assume that you are calling the Second_ViewController from storyboard instead of doing programmatically.
In that case, the correct instance of Second_ViewController can be accessed in prepareForSegue. For that, you need to set a Storyboard segue identifier, eg "Second_ViewController"
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"Second_ViewController"]) {
SecondViewController *aSecVC = segue.destinationViewController;
// Register the Delegate to self.So when we call the delegate method from secondVC, SendMessage will be call of ViewController
aSecVC.delegate = self;
}
}
If you use alloc-init or instantiateViewControllerWithIdentifier, when you are using a storyboard push segue, it will create another instance.
Yes as your instantiating a new instance of the second view controller. From what I could make out from your question, I guess if you obtain the instance of your secondViewController from the Navigation Stack it should work
I created a sample project for you to get the basic knowledge of how to pass data backward using NSUserDefaults. try this in GitHub. hope this will help to you. project url Pass data backward using NSUserDefaults in Objective-C

Access A UIImageView Outside Of Where It Was Declared

I have declared a UIImageView (IBOutlet UIImageView *character;) in a file called GameViewController.h and I am unsure how I can access this from another file CharacterSelectViewController.h.
All I need to do with it after I get it is to set the image. How can I access this UIImageView from another file?
First you need to get the existing instance of GameViewController that is currently on display. How you do that from CharacterSelectViewController depends on how they are related to each other and you may want to set up a delegate relationship / navigate the view controller stack to find the correct instance.
Once you have the instance you just access the property:
gameViewController.character.image = ...;
In any case, a delegate type relationship is generally better than navigating the view controller hierarchy. This could be as simple direct relationship or a generalised relationship using an #protocol.
If GameViewController presented CharacterSelectViewController as a modal, then you could use
GameViewController *gameViewController = (GameViewController *)self.presentingViewController;
If GameViewController pushed CharacterSelectViewController into its navigation controller, then you could use:
NSArray *viewControllers = self.navigationController.viewControllers;
GameViewController *gameViewController = (GameViewController *) viewControllers[viewControllers.count - 2];

Returning the selected cell value from table view controller on back button press

I have 2 table view controllers where I on button click on first controller, I am pushing to another view controller.
On the second table view controller, I have a list of items which is checkmarked upon selection. I want to return the selected value to the first view controller.
Also, please let me know how can I use that value in first view controller.
I cant use seagues and the second view controller is generic so I cannot set any of the variables of first view controller in it.
One option would be to create a delegate for that second view controller
In the .h you could declare
#protocol SecondControllerDelegate <NSObject>
- (void)selectionDidFinish:(NSArray*)objects;
#end
#interface SecondViewController : UIViewController
#property(nonatomic, weak) id<SecondControllerDelegate> delegate;
Then in your .m in view will disappear :
- (void)viewWillDisappear:(BOOL)animated{
[self.delegate selectionDidFinish:yourArray];
}
And in your first view controller you'd have to implement this protocol :
in .h :
#interface FirstViewController : UIViewController <SecondControllerDelegate>
and in .m
- (void)selectionDidFinish:(NSArray*)objects{
//Do whatever you want with selected objects
}
and of course when you create your second view controller you'd have to do :
SecondViewController *sVC = [[SecondViewController alloc] init];
sVC.delegate = self;
[self.navigationController pushViewController:sVC animated:YES];
A possible solution is to create a mutable object (NSMutableArray, NSMutableDictionary) in the parent controller and pass it to the child, so the child can modify it and when you are back to the parent - the mutable object will contain the modified values.
Another approach, which requires a little more knowledge is to use a protocol. The basic idea is to create a protocol and a delegate, so the child can "notify" the parent that it chose some values. You can check these examples:
http://www.theappcodeblog.com/2011/04/15/passing-data-between-views-tutorial-using-a-protocol-delegate-in-your-iphone-app/
http://iosdevelopertips.com/objective-c/the-basics-of-protocols-and-delegates.html
Please tell me if you need more information.
You can create delegates. Checkout the following link:
http://www.hardcodedstudios.com/home/ryan-newsome/simpledelegatetutorialforiosdevelopment

Send UITableView row From One tableviewController to another

I want to send a UITableViewCell at indexPath.row from one controller to another. I can remove the row using removeObjectAtIndex, but unable to send the removed row into another controller.
I'm trying to store the removed row in an NSMutableArray in one controller, but don't know how to populate it in another controller.
Below is the code -
ViewController *view= [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
view.anotherviewArray= [self.arrayFromAFNetworking objectAtIndex:indexPath.row];
If anyone can give me an idea, it would be helpful.
I believe it's bad practice to retain UI elements and pass them around your app. You should instead have some kind of a model containing your data, and pass this model from one view controller to the other. I'd recommend checking out tableview frameworks such as the free Sensible TableView framework, as they do an excellent job of providing such a model for you automatically.
I personally think that it's wrong approach to pass UI object as parameter to another controller.
As I would do it is create some object that encapsulates data model from this cell and pass this object to another view controller.
#interface DataObject : NSObject
#property id field1;
#end
UI part of cell can be easily copied in Interface Builder, so I don't see problem in that. Probably it would be great to have cell class that could fill necessary field from the object with data. This class you can use in both view controller that have to show the same cell
#interface CustomTableViewCell : UITableViewCell
- (void)customizeCellWithDataObject:(DataObject *)dataObject;
#end
I hope it makes sense to you
Assuming that you DO want to set the other data source with only this row, you need to pass it as an array.
view.anotherviewArray= [NSArray arrayWithObject:[self.arrayFromAFNetworking objectAtIndex:indexPath.row]];
But it's hard to tell from the little code that you have provided. I assume that since you are instantiating the viewController you are also transitioning to it below the provided code. If you are trying to set the array for a viewController already presented, you need to access that one, not create another, perhaps by having saved a reference to it an ivar within the current viewController or another accessible class.
I would also not name a ViewController view, it is confusing to anyone reading the code later on.
Editing for my comment below about traversing the hierarchy. Here is some code that I used in one iPad project to return the final presented viewController. This method is in the appDelegate. It is somewhat specific to my project, where there is only one navigationController. But you can adapt it to yours. You would test for a viewController that is of the class of your target view controller.
- (UIViewController *)topViewController {
UIViewController *rootViewController = self.window.rootViewController;
UIViewController *topViewController = rootViewController.presentedViewController;
while (topViewController && topViewController.presentedViewController) {
topViewController = topViewController.presentedViewController;
if ([topViewController isKindOfClass:[UINavigationController class]]) {
UIViewController *presentedViewController = [(UINavigationController *) topViewController topViewController];
if (presentedViewController) {
topViewController = presentedViewController;
}
}
}
return topViewController;
}
The other approach is to set a property to it when it is created and presented. We don't have enough code to get a good idea of your app as a whole. Where are you creating the ViewController instance that you are displaying? By that I mean where you are calling a segue to it, or pushing it onto a navigationController or call presentViewController. Wherever that is, you need to set a property or ivar to it. Let's say that you use a property in your appDelegate as a very generic case.
In your MyAppDelegate.h file you have
#property(nonatomic,strong) ViewController *viewController;
Wherever you first create it you set that property
MyAppDelegate *appDelegate = (MyAppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.viewController = [self.storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
I now think you are trying to add this to a mutableArray in the other ViewController. Then replacing your code from the tableViewCell above you would use
MyAppDelegate appDelegate = (MyAppDelegate)[[UIApplication sharedApplication] delegate];
[appDelegate.viewController.mutableDataArray addObject:self.arrayFromAFNetworking objectAtIndex:indexPath.row];
[appDelegate.viewController.tableView reloadData];
I will say that it is not great practice to use the appDelegate for the property. But it is a generic answer that would work. It's best to put it in a class which is common to the viewControllers that you are passing data between. Perhaps a single parent which holds these two viewControllers?

instantiateViewControllerWithIdentifier and pass data

I am using Storyboard in my app and I want to pass data from one view to another view.
Instead of using segues I am using instantiateViewControllerWithIdentifier. In this case I am instantiate from my first TableViewController to a NavigationController which has a second TableViewController attached because I need the navigation in the second TableViewController. Now I want to pass data from my first TableviewController, depending which row was clicked, to my second TableviewController. In this case newTopViewController would be my NavigationController but my problem is now how to pass data from firstTableViewController to the secondTableviewController.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = [NSString stringWithFormat:#"%#Top", [menuArray objectAtIndex:indexPath.row]];
UIViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
}
If you instantiate a navigationController, you can use the viewControllers property to get the inner viewController of the navigation controller.
Something like this:
UINavigationController *navigationController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
MBFancyViewController *viewController = navigationController.viewControllers[0];
// setup "inner" view controller
viewController.foo = bar;
[self presentViewController:navigationController animated:YES completion:nil];
newTopViewController.anyVariableToShow= anyVariableToSend;
I do this pretty often on a few of my apps...
//Create new VC
CookViewController *detailViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"CookVC"];
//Set recipe
[detailViewController setRecipe:recipe];
//Pop over VC (can be pushed with a nav controller)
[self presentPopupViewController:detailViewController animationType:MJPopupViewAnimationFade];
If you aren't using a navigation controller or segues, then I think you need to reconsider your app design.
Actually it's not just a data pass problem as this is a program control and data transfer question together.
Even you would have to rethink about your app's concept, as you'd like to use storyboard without the meaning of storyboard, it's up to you and I hope you have good reason to do what you do.
So when you decided not to use segue you lost the new and comfortable way of instantiating a new controller and transferring data with it and you have to do the transfer of control and the data in two distinct steps. When you instantiate another scene in storyboard (like you do with instantiateViewControllerWithIdentifier:) you just instantiated a new controller and transferred the control but not the data. Just think about it as you instantiated a new controller from a xib in an old way (so you have to use initWithCoder: or awakeFromNib in the second view controller as the storyboard will not call initWithName:bundle:), but did not do anything more.
So you will have a new controller (it named in the identity part of the second storyboard) which is hanging in the universe without any relationship or connection with anything else (as the storyboard picture illustrates it nicely) and you could do with it what you'd like.
So you'd like to do something and you need data from the previous storyboard (ViewController). What you need is making available those data to the second storyboard(ViewController), and as you know there are lot of solution for this which were available long time before even storyboard is existed.
So regarding your code, the "data transfer" is depending on your design, whether the two controllers are subclasses of each other or whatsoever...
If you don't like to deal with subclassing and like to decoupling them as much as possible, the best way just make a property of your data in the first controller and refer to them from the second (after importing the first's .h file) and just refer to it in it's viewDidLoad or in initWithCoder: or anywhere where you need them, as
secondViewControllerdata = firstViewControllerdata.thatDataProperty
Of course you can do the same in reverse and make a property of the second controller and refer to it in your first view controller.
You can define some parameter in UIViewController to receive data:
#property (assign) int param1;
#property (retain) NSMutableArray *param2;
and use below to pass the data:
[newTopViewController setParam1:XX];
[newTopViewController setParam2:XX];

Resources