NSArray blank - Passing between UIViewControllers - ios

I have an iOS application which needs to pass an NSArray between two ViewControllers. However when the NSArray gets passed its blank.... (in the view that it gets passed to).
Here is my code:
VIEW ONE - header file
// Detail view property - pass data on.
#property (nonatomic, retain) DetailView *data_pass;
VIEW ONE - implementation file
#synthesize data_pass;
NSArray *image_iphone = [[res objectForKey:#"results"] valueForKey:#"pictures"];
UIStoryboard *newStoryboard = [UIStoryboard storyboardWithName:view_name bundle:nil];
DetailView *firstvc = [newStoryboard instantiateInitialViewController];
self.data_pass = firstvc;
data_pass.input_image = image_iphone[indexPath.row];
[self presentViewController:firstvc animated:YES completion:nil];
VIEW TWO - header file
#property (nonatomic, retain) NSArray *input_image;
VIEW TWO - implementation file
#synthesize input_image;
NSLog(#"VIEW DID APPEAR LOG: %#\n\n", input_image);
In the first view controller "VIEW ONE" I have checked the NSArray that I am passing and it is NOT blank at all...
Here is the output I get in the second view controller "VIEW TWO":
VIEW DID APPEAR LOG: (
)
So what am I doing wrong?

So I figured out what was wrong in the end. But thank you to all the people who left comments, they helped a lot!!
The issue was with two things:
1) As #RamaniAshish said - I was passing indexPath.row and NOT the whole NSArray. For some reason this means that the contents of the array doesn't get passed.
2) The second issue was with one of my if statements which was checking for the wrong thing and so the correct array that was being passed in was not being checked in the second view controller.
Thanks for all you help fellow devs :)

Related

ObjectiveC - [self.view viewWithTag] returning null

I am completely stumped and have been researching for days. Probably something really simple that I am missing.
I have a ViewController which contains a custom UIView called GameView, and a UIView called buttonBox which contains a "next level" button. What I am trying to achieve is when the level is completed in GameView, it fires a function in my ViewController which shows the buttonBox so the user can click the "next level" button. It simply will not work.
I have attempted this in 3 ways, neither have worked:
Creating an IBOutlet in the ViewController, connecting it to the hidden UIView (and it was definitely connected) and calling setHidden:NO.
Calling the [self.view viewWithTag:xxx] and then calling setHidden:NO.
Using hidden=NO instead of setHidden:NO.
Relevant code for ViewController as follows:
#interface PlayViewController : UIViewController
#property GameView *gv;
#property (strong, nonatomic) IBOutlet UIView *buttonBox;
-(void) showButtonBox;
#end
#implementation PlayViewController
#synthesize buttonBox;
...
- (IBAction)showButtonBox {
UIView *uiv = (UIView*) [self.view viewWithTag:999];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Showing box function");
NSLog(#"%#", uiv);
uiv.hidden = NO;
});
}
#end
And my custom view:
#implementation GameView
...
dispatch_async(bgQueue, ^{
_loopRunning = true;
//NSLog(#"Calling main loop...");
while ([self loopRunning])
{
...
PlayViewController * pvc = [[PlayViewController alloc]init];
[pvc showButtonBox];
...
}
#end
The thing is, the variable uiv is returning null in NSLog, which is obviously why hidden is not working, but I have no idea why. It also didn't work when I was using IBOutlet.
Also, current output from NSLog is as follows:
2015-11-24 00:18:38.612 ib[12579:1264539] Showing box function
2015-11-24 00:18:38.612 ib[12579:1264539] (null)
Thanks in advance.
Correct Answer:
The problem was that I was using StoryBuilder to build my UI, but by using the alloc init method was creating a new view controller (which is never shown) instead of correctly referencing the view controller which was being displayed. This is achieved by passing the view controller being displayed to the view in the viewDidLoad function, see below:
#implementation PlayViewController
#synthesize buttonBox;
#synthesize gv;
- (void)viewDidLoad
{
[super viewDidLoad];
gv = [self.view viewWithTag:777];
[gv setPlayViewController:self];
}
...
Man, it's simple. Let's take a look at:
#implementation GameView
...
dispatch_async(bgQueue, ^{
_loopRunning = true;
//NSLog(#"Calling main loop...");
while ([self loopRunning])
{
...
PlayViewController * pvc = [[PlayViewController alloc]init];
[pvc showButtonBox];
...
}
#end
Here we have the issue:
dispatch_async(bgQueue, ^{
I assume, bgQueue stands for "background queue", which means this is not served by the main thread (the UI thread).
Having that said, it's quite naive to expect
[pvc showButtonBox];
to work properly. Just move this code into the main thread. For instance, you can just wrap the aforementioned line of code into a dispatch_async on the main queue. That should solve your probem, if your outlets and/or tags are OK. Cheers.
[[PlayViewController alloc]init];
This creates a new instance of PlayViewController. Where have you defined your outlets and views?
In a storyboard? You can't use this initialiser - nothing from the storyboard will be picked up, you have to use a segue or initializeViewControllerWithIdentifier:.
In a xib file? Is it called PlayViewController.xib? If not, it won't be picked up by the initialiser. Plain alloc/init of a view controller will only find a nib file as described in the documentation of the nibName property.
Do you really want alloc / init at all? Do you actually want to make a new view controller, or is one already on the screen?
From your comments it seems option 3 is the right answer. The PlayViewController is already on the screen, alloc/init is creating a new instance of it, which is never being put on screen, which never loads any views regardless of storyboards or nibs.
You need to get a reference to the existing instance of PlayViewController. Without knowing the structure of your app it's not too easy to say how that's done - is it presenting the game view? Is the game view a subview of the view controller's view? You may need to pass in a reference (weak) to the game view when it is created, at viewDidLoad, or set up an outlet in the storyboard.

Pass data between two ViewControllers [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 7 years ago.
I need to pass data between two ViewControllers but without UIButton, in a few words, I need to access a variable which is in other ViewController.
My code is:
LoginViewController *lvc;
NSString name=lvc.name;
This specific case might be a little easier than delegates.
From what I see, you're trying to pass login credentials (name/login/password/something). I would use two things depending on the actual matter here.
Either NSUserDefaults or -performSegueWithIdentifier:
NSUserDefaults is a file that is loaded in every app that you can read and edit, simply using the following commands :
Setting a variable :
NSString *aName;
[[NSUserDefaults standardUserDefaults]setObject:aName forKey:#"userName"];
Getting a variable :
NSString *aName = [[NSUserDefaults standardUserDefaults]objectForKey:#"userName"];
Note that you can save the following objects NSDictionary, NSArray, NSString, NSNumber, NSData, and probably a couple that I'm forgetting but someone can edit if I do.
Note that this file is loaded at every startup, so you don't wanna use that as a database but more of a small-sized storage easy to use, like for user name, preferences/settings, and stuff like that.
The other way is using performsegue between two controllers, but that requires storyboards.
Drag a segue between two of your controllers, name it (for example) fromLoginToHome. I'm assuming that the flow goes from the login controller to the home controller.
when you move between the two views (when the user presses "Login" for example), call this method
[self performSegueWithidentifier:#"fromLoginToHome" sender:self];
Then you'll need to implement this method, that is usually there but in a comment block (it's always like that when you create your Vc)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"fromLoginToHome"]){
HomeViewController *vc = (HomeViewController*)segue.destinationViewController;
vc.myName = _myName;
}
}
Xcode using delegate to pass data between controllers This is for child to parent by usuing delegates
And For parent to child,you can use segues simply.
HTH!enjoy Coding.
You can have a look of delegate method in here delegate. can you tell me if you are looking for delegate or not
Try using as below
FirstViewController.h
#interface FirstViewController: UIViewController
- (void)GetItNow;
FirstViewController.m
- (void)GetItNow{
NSLog(#"I acheived"); }
- (IBAction)goToSecondView:(id)sender {
SecondViewController* Second= [[SecondViewControlleralloc] initWithNibName:#"SecondViewController" bundle:nil];
rqVC.addId = self.addId;
[self.view addSubview:Second.view];
}
SecondViewController.h
#property (nonatomic, assign) id delegate;
SecondViewController.m
- (IBAction)Action_LoadFunds:(id)sender {
[self.view removeFromSuperview];
[_delegate GetItNow];
}

Pass NSMutableArray Data Between Views [duplicate]

This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 8 years ago.
I am having trouble passing my NSMutableArray data from one view to the other.
My view transition works the following way
Send View -> Recipients View
Recipients View -> Send View
In the recipients view I am grabbing the people I want to send my data to. Once I grab the people using an array, I go back to my send view to send those people that data.
In my send view I have the following NSMutableArray
#property (nonatomic, strong) NSMutableArray *sendTo;
I initialize it in viewDidLoad like so:
self.sendTo = [[NSMutableArray alloc] init];
In my Recipients View I have the following NSMutableArray
#property (nonatomic, strong) NSMutableArray *recipientsArray;
I initialize it in the viewDidLoad like so:
self.recipientsArray = [[NSMutableArray alloc] init];
I also have a back button in this controller which tries to handle the passing of the data in the recipientsArray. Please note this array does have data in it up until the point of the view switch.
- (IBAction)back {
SendView *send = [self.storyboard instantiateViewControllerWithIdentifier:#"View"];
send.sendTo = [NSMutableArray arrayWithArray:self.recipients];
[self dismissViewControllerAnimated:YES completion:nil];
}
Any idea why the array in my Send View is returning nil?
This code creates a brand new instance of SendView...
SendView *send = [self.storyboard instantiateViewControllerWithIdentifier:#"View"];
This code sets the sendTo property on the brand new instance of SendView.
send.sendTo = [NSMutableArray arrayWithArray:self.recipients];
At the end of the back method, this instance of SendView goes out of scope and is gone forever.
In conclusion, you must get a reference to your existing instance of SendView in order to do anything meaningful.

NSNotification sends value that get reset in viewDidLoad

I have this problem:
2 views called A and B, both are TableViewController.
A listen for notification, B sends notification
I'm not going to explain in detail, but for sake of simplicity it's like this:
A can display multiple types of data, B has a list of these types, selecting one row from B makes A load in it's tableView the right list of data.
While i'm in B i'm sending a notification like this
NSNumber *section = [NSNumber numberWithInt:indexPath.row];
NSDictionary *infoDictionary = [NSDictionary dictionaryWithObject:section
forKey:#"CurrentTableView"]
NSString *UpdateTableView = #"UpdateTableView";
[[NSNotificationCenter defaultCenter] postNotificationName:UpdateTableView
object:self
userInfo:infoDictionary];
Now in A i'm listening like this
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(updateTableView:)
name:#"UpdateTableView"
object:nil];
which calls the method
#property (strong, nonatomic) NSNumber *section;
// :::: Some code here ::::
- (void)updateTableView:(NSNotification*)note
{
_section = [[note userInfo] valueForKey:#"CurrentTableView"];
NSLog(#"%d",[_section intValue]);
[self.tableView reloadData];
}
and the NSLog works fine, i mean it prints the right value.
I'm using _section to discriminate in the TableView delegate methods what kind of data to load.
The problem is that the call to this method (after the notification is received) happens BEFORE the view is actually reloaded (viewDidAppear and so) which set my #property _section to 0, in this way every time my TableView loads the data standing behind the [_section intValue] == 0.
How could i solve this? I need something that don't gets reset every time the view loads itself. Any suggestion?
EDIT: navigation controller to move from B to A
MenuNavigationController *navigationController = [self.storyboard instantiateViewControllerWithIdentifier:#"contentController"];
AViewController *homeViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"homeController"];
navigationController.viewControllers = #[homeViewController];
Do you really need NSNotification ? Notifications are used where you want to update a view, and by update i mean that the view is already created.
What i would do is fairly simple, in B i would set your NSNumber *section as an ivar (if you display controller A some place different from where you post you notification). When you posted your notification you would just instantiate your ivar.
Then A would have a similar variable and when you want to display A :
AViewController *homeViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"homeController"];
homeViewController.section = section;
navigationController.viewControllers = #[homeViewController];
Perhaps your property section isn't synthesizing to use your instance variable _section. Does your synthesize line look like this:
#synthesize section=_section;
Otherwise the compiler will implicitly create an instance variable name section
UPDATE
As #Justafinger mentioned, as of Xcode 4.4, the ivar will be named _section if you completely leave out the #synthesize line. If you do explicitly synthesize, however, and don't assign the ivar name in the #synthesize line the ivar name will default to section.

How to pass data to parent view IOS

I know this question is asked once every two days. I can not see what I am doing wrong though.
I have a storyboard navigation controller based app.
My notification and pop / push segues works well, only thing is I can not add string to parents view NSmutablearray.
I want to add a string object to parent view's nsmutablearray. My decent code does not pass any data.
parent.h
#interface CreaatePlistTableViewController : UITableViewController<UITableViewDelegate, UITableViewDataSource>{
NSMutableArray *presenterList;
}
#property (nonatomic, strong) NSMutableArray *presenterList;
parent.m
NSString * const NOTIF_CreatePlist_UpdateTableview= #"CreatePlist/UpdateTableview";
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Private interface definitions for update tableview
*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#interface CreaatePlistTableViewController (private)
- (void)CreatePlistUpdateTableview:(NSNotification *)notif;
#end
#implementation CreaatePlistTableViewController
#synthesize presenterList=_presenterList;
- (void)viewDidLoad
{
[super viewDidLoad];
_presenterList=[[NSMutableArray alloc] init];
// Register observer to be called when logging out
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(CreatePlistUpdateTableview:)
name:NOTIF_CreatePlist_UpdateTableview object:nil];
NSLog(#"Presenter List: %#", _presenterList);
}
- (void)CreatePlistUpdateTableview:(NSNotification *)notif{
NSLog(#"Notification recieved");
NSLog(#"Presenter List: %#", _presenterList);
[_createPlistTableview reloadData];
}
child.h
#interface AddPresenterViewController : UITableViewController<UITextFieldDelegate,UIAlertViewDelegate>{
CreaatePlistTableViewController *crereaatePlistTableViewController;
}
#property(nonatomic,strong) CreaatePlistTableViewController *crereaatePlistTableViewController;
child.m
#synthesize crereaatePlistTableViewController=_crereaatePlistTableViewController;
//finished adding presenter
-(IBAction)finishedAddingPresenter:(id)sender{
//some xml string here
NSLog(#"final result XML:\n%#", writer.XMLString);
_crereaatePlistTableViewController=[[CreaatePlistTableViewController alloc]init];
//add object to parents view data source
[_crereaatePlistTableViewController.presenterList addObject:writer.XMLString];
//dismiss the view
[self.navigationController popViewControllerAnimated:YES];
//notify the parent view to update its tableview
[[NSNotificationCenter defaultCenter] postNotificationName:#"CreatePlist/UpdateTableview" object:nil];
}
Output
Notification recieved
Presenter List: (
)
So notification works when I click the button. But it does not pass object to nsmutablearray.
What I am doing wrong here ? How can I add an object to parent view's nsmutablearray?
It seems everything is good except your alloc of parent view object I am not that familiar with storyboard but You said you are using navigation navigation controller
so change this
_crereaatePlistTableViewController=[[CreaatePlistTableViewController alloc]init];
to
_crereaatePlistTableViewController= [self.navigationController.viewControllers objectAtIndex:0];
It may work I am not sure
You wrote this.
[_crereaatePlistTableViewController.presenterList addObject:writer.XMLString];
Do you ever initialize the array? No. Use the debugger and you will see that at this line the presenterList is nil.
Now as a point of style. Avoid using NSNotificationCenter to pass data or signaling other objects. #TheRonin gave a handy link. You should also look into some tutorials on Segues, because these are solved problems.
This is another related post that you might find interesting.

Resources