I have the following class:
#interface DiscountDetailViewController : UIViewController {
UILabel * titleLabel;
UILabel * offerLabel;
}
#property (nonatomic, retain) IBOutlet UILabel * titleLabel;
#property (nonatomic, retain) IBOutlet UILabel * offerLabel;
#end
and I tried to do the following in the previous view:
discount = [[DiscountDetailViewController alloc] initWithNibName:#"DiscountDetailViewController" bundle:nil];
discount.titleLabel.text = temp.vendor;
discount.offerLabel.text = temp.description;
[self.navigationController pushViewController:discount animated:YES];
The issue is that, discount.titleLabel.text when printed is always null... I think it's because I define the titleLabel using interface builder.. so is there a way to resolve this?
I've hooked it up with IB as well..
i don't believe the iboutlets get hooked up until the view is on screen for the first time.
you could try setting the label after its displayed, or add another property to store the label text, then set the iboutlet label based on this new property in viewDidLoad in your DiscountDetailViewController.
If your outlets are properly connected then it is only because your titleLabel will not be available until your viewIsLoaded around -(void)viewDidLoad, I recommend you use an NSString property that can set the title label once view is loaded and update it when it is changed (override setter), or if you know your view is about to show try calling view first.
discount = [[DiscountDetailViewController alloc] initWithNibName:#"DiscountDetailViewController" bundle:nil];
//Force view to load, do not really recommend (though for some reason I am showing you how)
[discount view];
discount.titleLabel.text = temp.vendor;
discount.offerLabel.text = temp.description;
[self.navigationController pushViewController:discount animated:YES];
Related
I have a view controller that has navigation bar with a done button, and two text fields. When the done button is pressed, the method postInfo is called. Here is the implementation:
- (void)postInfo{
ListingViewController* lvc = [[ListingViewController alloc] init];
NSString* listingName = listingNameField.text;
NSString* listingPrice = listingPriceField.text;
NSLog(#"%#", listingName);
NSLog(#"%#", listingPrice);
[lvc.titleLabel setText:listingName];
[lvc.priceLabel setText:listingPrice];
[self.navigationController pushViewController:lvc animated:YES];
}
Here ListingViewController.h:
#import <UIKit/UIKit.h>
#interface ListingViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *priceLabel;
#property (weak, nonatomic) IBOutlet UILabel *titleLabel;
#end
The UILabel's are set through a xib file and are empty. Will post whatever other code is needed upon request.
At the time you do that push, the next controller's view hasn't been loaded yet, so you can't access its views. You need to create NSString properties in ListingViewController and pass a string to those in your postnfo method. Then in ListingViewController's viewDidLoad method, use those properties to populate the labels (which will have been loaded by the time viewDidLoad runs).
Change your code to this.
- (void)postInfo
{
ListingViewController* lvc = [[ListingViewController alloc] init];
[lvc view]; // loads the view
NSString* listingName = listingNameField.text;
NSString* listingPrice = listingPriceField.text;
NSLog(#"%#", listingName);
NSLog(#"%#", listingPrice);
[lvc.titleLabel setText:listingName];
[lvc.priceLabel setText:listingPrice];
[self.navigationController pushViewController:lvc animated:YES];
}
This happens because until the view property of the view controller is accessed, the view will not be loaded and all of the subviews are nil. They can be configured after viewDidLoad is called on the view controller being pushed. Calling [lvc view] loads the view immediately.
I usually get this too (in the example of when using segues). I get around it by setting an NSString property instead of an IBOutlet during prepareForSegue of the destinationController. Then during viewDidLoad of the next View Controller, I take the value of the property and assign it to the UILabel.
You may find the explanation in this answer useful: https://stackoverflow.com/a/8094146/2358334
If you set a breakpoint just after the line you call
testViewController *viewController = segue.destinationViewController;
when you build and run the project, you will find that the UITextField
property in the destinationViewController is not allocated and
initiated (memory is 0x0) at the breakpoint. Meanwhile the NSString
property is already allocated and initialised (so you can set its
value).
Try to do this
first you need to load the view (push viewcontroller) and then you can access the properties (because you have created views by IBOutlet
- (void)postInfo{
ListingViewController* lvc = [[ListingViewController alloc] init];
NSString* listingName = listingNameField.text;
NSString* listingPrice = listingPriceField.text;
NSLog(#"%#", listingName);
NSLog(#"%#", listingPrice);
[self.navigationController pushViewController:lvc animated:YES];
[lvc.titleLabel setText:listingName];
[lvc.priceLabel setText:listingPrice];
}
i have two screen. i want click button first screen after navigation bar change in second screen.
i using storyboards
first screen code
-(IBAction) ChangeSecondPageTitle: (id) sender {
SecondViewController *second=[[self storyboard] instantiateViewControllerWithIdentifier:#"second"];
second.modalTransitionStyle=UIModalTransitionStyleFlipHorizontal;
second.detailTitle.topItem.title=#"example";
[self presentModalViewController:second animated:YES];
}
second screen.h
#property (weak, nonatomic) IBOutlet UINavigationBar *detailTitle;
I guessing you are trying to set title for your second screen navigation bar.
Use a navigation controller to present your second screen.
In SecondDetailViewController instance, maintain a NSString property.
#property (strong, nonatomic) NSString *navBarTitle;
In viewDidLoad, just set the title.
[self setTitle:navBarTitle];
Actually the reason your code is not working is you set the property to your nav bar and then your viewDidLoad get called. In viewDidLoad it loads the nib file and return new allocated navBar. So to Solve this take a global string set it from first view and then in second in viewDidLoad set your navbar's title. Follow
Adithya's answer for that.
In second screen declare a property
#property (strong, nonatomic) NSString *newTitle;
and in viewDidLoad
self.title = _newTitle;
and in your first screen
...
second.newTitle = #"NEW_TITLE";
I've a problem with some label. I made a public method that takes information from a table view and shows this info in 3 label, a text view and it load a pic from the web. I setup all the variable in the table view didSelectRowAtIndexPath method, but I'm having some issue to display that info. I made so:
in the table view controller I called the other method so:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.detailCharacterViewController = [[DetailCharacterViewController alloc] init];
[self.detailCharacterViewController setupDetailViewControllerWithName:[self.arrayCharacters[indexPath.row] objectForKey:#"name"] andSurname:[self.arrayCharacters[indexPath.row] objectForKey:#"surname"] andKind:[self.arrayCharacters[indexPath.row] objectForKey:#"kind"] andDescription:[self.arrayCharacters[indexPath.row] objectForKey:#"description"] andImage:[self.arrayCharacters[indexPath.row] objectForKey:#"URLpic"]];
}
and I implemented the method so:
- (void)setupDetailViewControllerWithName:(NSString*)name andSurname:(NSString *)surname andKind:(NSString*) kind andDescription:(NSString*)description andImage:(NSString*)url {
NSLog(#"name = %#", name);
self.labelName.text = name;
self.labelSurname.text = surname;
self.labelKind.text = kind;
self.textDescription.text = description;
NSURL *urlPic = [NSURL URLWithString:url];
NSData *dataPic = [NSData dataWithContentsOfURL:urlPic];
[self.imagePic setImage:[UIImage imageWithData:dataPic]];
}
If I look to the log i see the right things, but if I look to the GUI on iPhone or iPhone simulator it will remain blank. What's wrong with this code?
Thank you for the suggestion.
#Alex Blundell
#import <UIKit/UIKit.h>
#interface DetailCharacterViewController : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *labelName;
#property (weak, nonatomic) IBOutlet UILabel *labelSurname;
#property (weak, nonatomic) IBOutlet UILabel *labelKind;
#property (weak, nonatomic) IBOutlet UIImageView *imagePic;
#property (weak, nonatomic) IBOutlet UITextView *textDescription;
- (void)setupDetailViewControllerWithName:(NSString*)name andSurname:(NSString *)surname andKind:(NSString*) kind andDescription:(NSString*)description andImage:(NSString*)url;
#end
The problem is that your DetailCharacterViewController's view is not loaded yet when you call setupDetailViewControllerWithName:..., so none of the outlets are connected (yet). Instantiating a view controller via alloc-init does not load its view automatically.
You could force loading the view by calling [self view] at the beginning of your setup method. This works because accessing the view property will automatically load the view if it wasn't loaded before.
Alternatively, you could make the name, surname, etc. NSString properties of the view controller and set the corresponding labels in viewDidLoad.
Are you using Interface Builder/Storyboards to design your interface? Have you made sure to connect the IBOutlets for each UITextField/View?
You should identify the objects in the header file on your view controller class, and ensure they're prefixed by IBOutlet for them to appear in Interface Builders connections pane. E.g.
IBOutlet UITextField labelName;
[...]
Then you need to go to IB and go to the connections pane for the view controller to connect each text field/view.
This problem happened to me as well.
It has to do with the fact that iOS actually hooks up your outlets really really late.
If you put a breakpoint in your setupDetailViewControllerWithName: and check your IBOutlet variables, they will be nil. That's why you are seeing a blank view. (The good old nil erroring)
The work-around I will do is to declare properties in the DetailCharacterViewController class. (Such as #property (copy, nonatomic) NSString* name).
And in the place where you are calling setupDetailViewControllerWithName:, set those properties instead such as:
self.detailCharacterViewController.name = name;
Finally in your DetailCharacterViewController's viewDidLoad:, you set the values of the labels using the saved properties. (The outlets are for sure hooked up then).
(By the way, this problem exists for prepareForSegue: as well. The destination view controller's outlets are all still nil in prepareForSegue:. So you cannot set them directly there yet)
I have two views, and i'm trying to show text that i getting from first view in UITextField of another . Second view shown by - (source) so methods ViewWillAppear and ViewDidLoad won't work. And viewDidLoad method of second view is runs when app is started.
I'm tried to make method of second class
secondClass.h:
#property (strong, nonatomic) IBOutlet UITextField *itemName;//all hooked up in storyboard
-(void)SetName:(NSString *)name;
secondClass.m:
-(void)SetName:(NSString *)name{
NSLog(#"%#",name);
itemName.text = name;//itemName - textField
}
and use it in first one:
secondViewConroller *secondView = [[secondViewConroller alloc]init];
[secondView SetName:#"Bill"];
NSlog shows "Bill" but textField.text won't change anything.
My guess that app shows UITextField without changes because it shows second view that it gets from viewDidLoad method and i need to update it somehow
My question: What is the best approach to change attributes of UI elements from different classes?
Easiest way:
secondViewConroller.h :
#property NSString * conversationName;
secondViewConroller.m :
#synthesize conversationName;
-(void)SetName:(NSString *)name{
NSLog(#"%#",name);
itemName.text = conversationName
}
On alloc:
secondViewConroller *secondView = [[secondViewConroller alloc]init];
conversationName = #"Set this text";
[secondView SetName:#"Bill"];
I would suggest you to read about Protocols after that.
Easiest way:
in
secondViewConroller.h :
#property (nonatomic, retain) NSString *stringName;
secondViewConroller.m :
#synthesize stringName;
and in viewDidLoad method you write this line
itemName.text = stringName
On alloc:
secondViewConroller *secondView = [[secondViewConroller alloc]init];
secondView.stringName = #"Set this text";
guess there is something wrong with your itemName variable if it appears to get to the nslog.
did you create a referencing outlet in the interface builder for the textfield?
otherwise you can get the right textfield by tag, in IB put for instance tag 1 on the textfield and do in code:
UITextField *tf=(UITextField*)[self.view viewWithTag:1];
tf.text=name;
(replace self.view for the view holding the textfield, if not directly in the main view)
So i found a solution: There's was something wrong with calling method SetName: with parameters that i getting from first UIViewController.
Basically the solution is : create NSObject and put in there value from first UIViewConroller and then use it in second.
This TUTORIAL helped me to resolve the problem.
Im new to iphone development and after lots of reading on it im still trying to figure out how UIViews operate properly. I have been playing about with it and i this is where i am at so far:
I have created a new xcode project using the view-based application. I have my MMAppViewController classes and i created a new UIViewController subclass called "Level1View".
There is a button titled "Level 1" that takes me to the "Level1View" viewController. In this viewController there is there is a "next" button, a "main menu" button (that returns to MMAppViewController) and there is a label, currently titled "Level 1".
My problem is that the code i have used to change the title of label does not work! Does anyone know why this is? Here is my code:
#class MMAppViewController;
#interface MMAppAppDelegate : NSObject <UIApplicationDelegate> {
UIWindow *window;
MMAppViewController *viewController;
}
#property (nonatomic, retain) IBOutlet UIWindow *window;
#property (nonatomic, retain) IBOutlet MMAppViewController *viewController;
#end
and
#implementation MMAppViewController
-(IBAction)pushLevel1{
Level1View *level1View = [[Level1View alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:level1View animated:YES];
}
...
and
#import <UIKit/UIKit.h>
#interface Level1View : UIViewController {
IBOutlet UILabel *labelTitle;
}
-(IBAction)pushBack;
-(IBAction)pushNext;
#end
and
#import "Level1View.h"
#import "MMAppViewController.h"
#implementation Level1View
-(IBAction)pushBack{
MMAppViewController *MainView = [[MMAppViewController alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:MainView animated:YES];
}
-(IBAction)pushNext{
[labelTitle setText:(#"Thanks for playing :)")];
}
- (void)didReceiveMemoryWarning {
...
Currently the app runs but the label wont change when i hit the "next" button. Can anyone help?
are you sure a UINavigationController isn't a better tool for the job you want to do? That will make it easy for you to manage a stack of UIView objects.
That said, have you tried adding logging to make sure your pushNext method is getting called? where is labelTitle declared? Did you use a XIB or not?
Did you bind the Label in Interface Builder to the labelTitle outlet in your Level1View?
If you forget that step, the outlets won't work. Even after several years, I still forget this step sometimes.
--Mike
are you sure you connected the label in IB?
and if you set a property "#property (nonatomic, retain) IBOutlet UILabel *labelTitle;" in Level1View.h you can access it from Main View:
Level1View *level1View = [[Level1View alloc] initWithNibName:nil bundle:nil];
[self presentModalViewController:level1View animated:YES];
level1View.labelTitle.text = #"something";
[level1View release];
The other thing you shouldn't present the Main View Controller again instead dismiss the Level1View with:
#implementation Level1View
-(IBAction)pushBack{
[self dismissModalViewControllerAnimated:YES];
}
//
and maybe the problem is [[Level1View alloc] initWithNibName:nil bundle:nil] you have to specify the nib you want to load e.g. [[Level1View alloc] initWithNibName:#"Level1View" bundle:nil]
Declare labelTitle as a property in your header file, and synthesize labelTitle in your .m - as long as labelTitle is hooked up through interface builder the rest of your code is fine.
.h
#property (nonatomic, retain) IBOutlet UILabel *labelTitle;
.m
#synthesize labelTitle;
Then your setter call will work. (also, dot-notation works for synthesized properties so you may as well use it)
change
[labelTitle setText:(#"Thanks for playing :)")];
to
labelTitle.text = #"Thanks for playing :)";
Synthesizing a property will create setter and getter methods at runtime. Read: The Objective-C Programming Language