I'm trying to pass some values from a view to another, but the values are always (null). Here my code.
First:
[self performSegueWithIdentifier:#"Thanks" sender:self];
Then:
-(void)prepareForSegue:(UIStoryboardSegue *)segue
{
ThanksViewController *vc = [segue destinationViewController];
[vc set_event_image_url:[NSString stringWithFormat:#"bla bla bla %#.png", event_id]];
[vc set_event_name:eventTitle];
}
In the receiver I'm initiating the variables.
#property(nonatomic,copy) NSString* _event_name;
#property(nonatomic,copy) NSString* _event_image_url;
AND
#synthesize _event_image_url;
#synthesize _event_name;
The values are now (null). Any Ideas why it fails? The segue is added to the storyboard too.
I would remove the underscores from your property names - it's not the standard way of naming things in objective-c and it's just possible that it could be confusing things (cocoa by default will synthesise you instance variables that begin with an underscore).
#property(nonatomic,copy) NSString* eventName;
#property(nonatomic,copy) NSString* eventImageUrl;
You can also remove your synthesize statements - objective-c will do your synthesizing for you, so they're not necessary.
You would then call [vc setEventTitle:blah];
However, the main issue is that you've implemented prepareForSegue incorrectly! The proper method signature should be:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender;
Add the sender parameter and you should find it'll be called.
Related
I am trying to access an array defined as property on the parent view from child view and I get an empty array. here is what I did. could someone shed some light please!
FirstTableViewController.h
#interface FirstTableViewController : UITableViewController
#property (nonatomic,retain) NSMutableArray *SomeItems;
#end
in my FirstTableViewController.m. I have code that initialized the SomeItems with values. This has been verified
On the FirstTableViewController view there is a button that displays a second SecondTableView
in SecondTableViewController.m I have
#import "FirstTableViewController.h"
#import "SecondTableViewController.h"
- (void)viewDidLoad
{
[super viewDidLoad];
FirstTableViewController * objParent;
NSLog(#"count = %i",[objParent.SomeItems count]); //this return 0
}
thanks in advance!
EDITED
ToDoListTableViewController.h
#interface ToDoListTableViewController : UITableViewController
#property (nonatomic, strong) NSMutableArray *toDoItems;
- (IBAction)unwindToList:(UIStoryboardSegue *)segue : (id) sender;
#end
ToDoListTableViewController.m
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
//Attempt to pass toDoItems to new view controller.
//CompleteTableViewController.toDoItems = [self.toDoItems copy]; //this line caused compiler error saying toDoItems not found on object of CompleteTableViewController
CompleteTableViewController * objChild = (CompleteTableViewController*)[segue destinationViewController];
if(objChild != nil)
objChild.toDoItems = [self.toDoItems copy];
//sorry for weird code, as I don't really understand how this method really works.
//but I have a feeling I am just some inches away from getting it to work the way i want
}
CompleteTableViewController.h
#interface CompleteTableViewController : UITableViewController
#property (nonatomic,copy) NSMutableArray *toDoItems;
#end
CompleteTableViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"#%i record(s) in Complete Table View", [toDoItems count]);
}
Thanks again!
It is clear that you miss the basilar concept of the OOP.
You declared this:
FirstTableViewController * objParent;
but first of all it is not initializated and second it doesn't point to your instanced viewController.
Other things but that at this point become secondary are:
if you are using ARC, declare the property strong instead of retain;
method and variable should respect the Camel methodology so is not SomeItems but is someItems;
So if you are opening a viewController from another and you want access to that array, the best thing that you could do is pass that array and so have a property like this also in the second viewController:
#property (nonatomic,copy) NSArray *someItems;
and when you press the button in the first viewController, before push the second viewController:
secondViewController.someItems = [self.someItems copy];
Note that in the second view controller the array is not mutable, because probably you want just access to the informations. But this depend from you.
Is a little bit hard explain you more because i see that you are really a newbie. But, i hope to help you.
You need to pass a reference for the parent object through to the child on creation, or simply pass a reference to the array itself.
From Matteo suggestion, this seems to solve my issue
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UINavigationController *navigationController = segue.destinationViewController;
CompleteTableViewController *objChild = (CompleteTableViewController *)navigationController.topViewController;
if(objChild != nil){
objChild.toDoItems = [self.toDoItems copy];
}
}
thanks Matteo.
In the SecondTableViewController, you've declared the FirstTableViewController in viewDidLoad, but that does not mean it's pointing to your previously created FirstTableViewController (you've made no assignment). Before viewDidLoad is called, you need to pass the FirstTableViewController to the SecondTableViewController, assign it to a variable that's not local in scope, and then you can access the FirstTableViewController and/or its SomeItems inside viewDidLoad.
Without knowing more of your design or what you're trying to accomplish, it'd be best to pass SomeItems to SecondTableViewController as part of initializing it if that's all you need from FirstTableViewController. If the state of what you're accessing is going to change as you are going from controller to controller, I'd highly recommend you spend more time reading up on Model-View-Controller (MVC), delegation and possibly Key-Value Observation (KVO). You're missing some fundamental knowledge.
Edit: also agree on naming, SomeItems should be someItems.
I have two view controllers
DetailViewController
BlogViewController
I have a 'push' set-up on the storyboard with the identifier 'ShowBlog'
i need to send the title of the blog from the UILabel below on the DetailViewController:
#property (strong, nonatomic) IBOutlet UILabel *TitleLabel;
to a UILabel on the BlogViewController called BlogTitleLabel:
#property (strong, nonatomic) IBOutlet UILabel *BlogTitleLabel;
i know i need to use:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"ShowBlog"]) {
// Im struggling with the code
}
}
But im struggling with the code to go in it
Use NSUserDefaults the code goes something like this:
Store the title:
[[NSUserDefaults standardUserDefaults] setObject:label.title forKey:#"nameForStoredVariableHere"];
[[NSUserDefaults standardUserDefaults] synchronize];
Retrieve the stored title:
NSString *storedTitle = [[NSUserDefaults standardUserDefaults] objectForKey:#"nameForStoredVariableHere"];
After that you're free to use the title as you please
prepareForSegue is called before destination VC's viewDidLoad so don't try to access any view object of destination view controller in prepareForSegue. Its better you create a string property in destination and set that in prepareForSegue method. In destination viewController's viewDidLoad set it to label.
You should not try to send data from label to label. Labels are view objects. They display information and collect input from the user. They do not store information.
Also, you should never, ever try to manipulate another view controller's views directly. That violates the other view controller's encapsulation.
Both view controllers should have NSString properties for this. Let's call it blogTitle on both VCs.
Your DetailViewController should set it's blogTitle somewhere during it's setup, and then in viewWillAppear:animated, display that value to it's titleLabel outlet:
- (void) viewWillAppear: animated;
{
[super viewWillAppear: animated];
self.titleLabel.text = self.blogTitle;
//your other code here
}
Then, in your prepareForSegue:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"ShowBlog"])
{
BlogViewController *theBlogController = [segue destinationViewController];
theBlogController.blogTitle = self.blogTitle; //Pass the blog title to the other VC
}
}
And then in the BlogViewController's viewWillAppear, copy the blogTitle to it's title label:
- (void) viewWillAppear: animated;
{
[super viewWillAppear: animated];
self.titleLabel.text = self.blogTitle;
//your other code here
}
Note that Cocoa/iOS programming has strong naming conventions that you should follow. Only filenames and class names should start with a capital letter. Method names, instance variable names, and property names should start with a lower-case letter. So your TitleLabel should be titleLabel, and BlogTitleLabel should be blogTitleLabel.
I am doing the following:
#ViewController1.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Transferring");
guestViewController *controller = [segue destinationViewController];
[controller.label isEqualToString:self.num_value.text];
}
However when the view is loaded, the text does not run through or show up in the label. I have done this in past programs and it has worked on Xcode 4. However, for some reason in Xcode 5 it is not working for me. Is there something else that I need to implement to make this work in Xcode?
Add this to your guestViewController's header file :
#property (nonatomic, strong) NSString *value;
The your prepareForSegue method becomes something like this :
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Transferring");
guestViewController *controller = [segue destinationViewController];
[controller setValue : self.num_value.txt];
}
isEqualToString is for comparison! Not to be used for assigning values.
Then in your viewDidLoad method, add this :
[textLabel setText : value];
[controller.string isEqualToString:self.num_value.text];
isEquelToString only check is controler.string is the same or not as self.num.value.text.
- (BOOL)isEqualToString:(NSString *)aString
Returns a Boolean value that indicates whether a given string is equal
to the receiver using a literal Unicode-based comparison.
Read the apple documentation
your can pass your string to the another controller like this:
In guestViewController's h file :
#property (nonatomic, strong) NSString *theStringWhatYouWantToGet;
and in prepareForSegue:
controller.theStringWhatYouWantToGet = self.num_value.text;
I am using the following to create a reference to a view controller in my code like this:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"detailSegue"]){
NSIndexPath *indexPath=[self.tableView indexPathForSelectedRow];
TRDetailViewController *vc=segue.destinationViewController;
vc.item=self.items[indexPath.row];
[vc setValue:self forKeyPath:#"delegate"];
[vc setValue:indexPath.row forKeyPath:#"itemIndex"];
}
}
and this is declared as in TRDetailViewController
#interface TRDetailViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *detailLabel;
#property NSString *item;
#property (nonatomic, weak)id delegate;
#property NSInteger itemIndex;
- (IBAction)deleteItem:(id)sender;
#end
but I get the following error
and I'm not sure why. I am trying to pass the location in an index of the cell selected in a UITableView. If a better way, please let me know. Why am I getting this error?
thx
setValue:forKey: is expecting an object for its value argument and you are passing it a primitive (in this case, an integer). You can work around this by amending your method to read as follows:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([segue.identifier isEqualToString:#"detailSegue"]){
NSIndexPath *indexPath=[self.tableView indexPathForSelectedRow];
TRDetailViewController *vc=segue.destinationViewController;
vc.item=self.items[indexPath.row];
[vc setValue:self forKeyPath:#"delegate"];
[vc setValue:[NSNumber numberWithInt:indexPath.row] forKeyPath:#"itemIndex"];
}
}
And then access it like:
[[vc valueForKey:#"itemIndex"] intValue];
setValue:forKeyPath: requires an object (i.e. id) as first argument.
You are instead passing a NSInteger.
You will have to use an object type, which means to turn your itemIndex into a NSNumber.
Then you can store it using
[vc setValue:#(indexPath.row) forKeyPath:#"itemIndex"];
and retrieve it by
NSInteger myIndex = [vc valueForKey:#"itemIndex"].integerValue;
I've got a question concerning my Storyboard. I want to change the value of a string which is in ViewA through a segue. That means that ViewB should do the segue and in preparation for that changing the value of the string in ViewA. My problem is now, that the value of my string stays unchanged.
ViewA.h file:
#interface NewViewController : UITableViewController <MKAnnotation>
{
NSString *longString;
}
#property (weak, nonatomic) NSString *longString;
ViewB.m file:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"transmitCoordsToNew"])
{
NewViewController *controller = (NewViewController *)segue.destinationViewController;
controller.longString = [NSString stringWithFormat:#"%f", segueLong];
}
}
Any idea why the variables stay unchanged or why I can't see any changes on further operating in ViewA?
Thanks in advance,
Phil
I'm not sure where your variable segueLong comes from, but having a weak reference to longString is most likely what's causing the problem. Change that to a strong reference and see if it works then.
If in prepareForSegue your NewViewController *controller is receiving a valid (non nil) value from [NSString stringWithFormat:#"%f", segueLong]; I am about 90% sure that the 'weak' property attribute is responsible for the value turning to nil.
Here's why!
[NSString stringWithFormat:#"%f", segueLong] has a scope limited by the prepareForSegue method, also it has no owner (aka no reference is counted for it). Even if segueLong has an owner and will not be released by arc, the resulting NSString from stringWithFormat does not!
What you need to do is change weak, to strong.
:
#interface NewViewController : UITableViewController <MKAnnotation>
{
__strong NSString *longString;
}
#property (strong, nonatomic) NSString *longString;
This ensures that the string generated by NSString stringWithFormat will belong to your NewViewController!