Im using a custom ModalViewController called MZFormSheetController to display a Detail View for UICollectionView. Currently I have created properties in the modal view controller such as these :
#property (strong,nonatomic) NSString *user;
#property (strong,nonatomic) NSString *caption;
#property (weak, nonatomic) IBOutlet UILabel *username;
#property (weak, nonatomic) IBOutlet UILabel *captiontext;
And I attempt to set the display of the detail view controller when the user taps on the UICollectionViewCell like this:
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSDictionary *entry = [self entries][indexPath.row];
NSDictionary *text = [self entries][indexPath.row];
ModalViewController *m = [self.storyboard instantiateViewControllerWithIdentifier:#"modalView"];
m.entry = [self entries][indexPath.row];
m.text = [self entries][indexPath.row];
m.user = entry[#"user"][#"full_name"];
m.caption = text[#"caption"][#"text"];
MZFormSheetController *formSheet = [[MZFormSheetController alloc] initWithViewController:m];
formSheet.transitionStyle = MZFormSheetTransitionStyleDropDown;
formSheet.shouldDismissOnBackgroundViewTap = YES;
[formSheet presentAnimated:YES completionHandler:^(UIViewController *presentedFSViewController) {
}];
formSheet.didTapOnBackgroundViewCompletionHandler = ^(CGPoint location)
{
};
}
I have created two labels in storyboard for the modalviewcontroller and I attempt to make them equal the caption and user values from the MainViewController like this
[self.username.text isEqualToString:self.user];
[self.captiontext.text isEqualToString:self.caption];
However after all this the labels of the modal view controller still say label like this..
Your labels are not being updated to the correct values because the -isEqualToString: method is used to test whether two NSStrings are equal, and it doesn't actually set the value of any NSString. If you want to assign a value to a string variable, you do it the same as you would assign any other variable. Therefore, in order to set the labels properly, you just need to assign the text property of the UILabels, like this:
self.username.text = self.user;
self.captiontext.text = self.caption;
Did you set username and captiontext inside your ModalViewController in viewDidLoad method ? After init from storyboard, all IBOutlets are nil, you need to setup then inside viewDidLoad.
- (void)viewDidLoad
{
[super viewDidLoad];
self.username.text = self.user;
self.captiontext.text = self.caption;
}
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'm having some trouble understanding how variable values are passed from one view to another. I have a UITextField in the firstview that the user enters a number into. When the user taps a button, that number is multiplied by 2 and the result is displayed on a UILabel in the second view. This is what I have thus far
FirstViewController.h
#interface FirstViewController : UIViewController{
UITextField *numberTextField;
NSNumber *aNumber;
}
#property (nonatomic, retain) IBOutlet UITextField *numberTextField;
#property (nonatomic) NSNumber *aNumber;
-(IBAction)calculate;
#end
FirstViewController.m
#implementation FirstViewController
#synthesize numberTextField, aNumber;
-(double)doubleNumber{
double number = [numberTextField.text doubleValue] * 2;
return number;
}
-(IBAction)calculate{
self.aNumber = [NSNumber numberWithDouble:[self doubleNumber]];
}
//more default code continues below
SecondViewController.h
#import "FirstViewController.h"
#interface SecondViewController : FirstViewController{
UILabel *numberLabel;
}
#property (nonatomic, retain) IBOutlet UILabel *numberLabel;
#end
SecondViewController.m
#implementation SecondViewController
#synthesize numberLabel;
- (void)viewDidLoad
{
[super viewDidLoad];
numberLabel.text = [NSString stringWithFormat:#"%#",aNumber];
}
Best and Easy Way to store value globally
set you object with your keyword
[[NSUserDefaults standardUserDefaults] setObject:#"Ajay" forKey:#"name"];
than get that object any where in you project
NSString *name = [[NSUserDefaults standardUserDefaults] objectForKey:#"name"];
You should accomplish what you want by using a segue. Create a segue in your storyboard and then call it in your firstviewcontroller with - (void)performSegueWithIdentifier:(NSString *)identifier sender:(id)sender. Then to pass data, import your secondviewcontroller.h file with a property for the value you want to pass and setup - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender.
In that method you can pass things by using [segue.destinationViewController ###call the setter for the property in your secondViewController.h file###];
If this isn't clear, or you need more help just let me know.
I'm assuming that the FirstViewController is instantiating the SecondViewController. If that is so, then you just pass aNumber to the SecondViewController using an additional property:
// add an additional property to the SecondViewController
#property (nonatomic, retain) NSNumber *aNumber;
When you instantiate the SecondViewController inside the FirstViewController, you just pass that value to the SecondViewController before you load it:
// inside FirstViewController
SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
secondViewController.aNumber = aNumber;
// inside SecondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
numberLabel.text = self.aNumber;
}
Mmm... Pay attention to not confuse views and viewControllers!!!
A viewController can manage more than a view. For example in your code you have a UITextField, a UILabel and probably a UIButton. These are all views that are managed by two viewsController (FirstViewController and SecondViewController).
As long as you have so few views to work with you can use just one viewController and pass the value you want to your UILabel directly:
- (void)calculateAndPassValue
{
aNumber = [NSNumber numberWithDouble:[self doubleNumber]];
numberLabel.text = [NSString stringWithFormat:#"%#",aNumber];
}
Otherwise, if your goal is passing variable values from one viewController to another. Well... There are many ways you can obtain that, for example:
Creating an ivar.
Using a singleton.
Saving your data in NSUserDefault.
Creating a database on disk.
First and second cases are good if you need to manage your data while your app is running. Third and fourth if you want to memorize your data for future use and retrieve them at next start up.
Try to search keys like ivar, singleton, NSUserDefault and you'll find many discussions and lines of sample code.
I'm making an app that behaves something like the default Messages.app in iPhone where a user composes a text message in a UITextField and upon tapping the Send button, the value of the UITextField in ComposeViewController will be transferred to the table cell's UILabel in a custom cell in MasterViewController and also to the DetailViewController where another UILabel will get the text value from the UITextField. The DetailViewController is the ViewController loaded when the user taps the cells from the UITableViewCells.
I actually read related articles below but it doesn't work on my end.
How to send the text from textfield to another class?
How to see text from one text field in another text field?
How to send text field value to another class
Can you please guide me on how to properly implement this? I know it's easy. I just don't know why it's not working. ComposeVC is a ModalViewController while DetailVC is the view that loads when the user taps the cell in the MasterVC's table.
Thanks a lot!
Below is my code for ComposeVC.h:
UITextField *messageTextField;
#property (nonatomic, retain) IBOutlet UITextField *messageTextField;
- (IBAction)buttonPressed:(id)sender;
for ComposeVC.m
synthesize messageTextField;
-(IBAction)buttonPressed:(id)sender
{
DetailVC *detailVC = [[DetailVC alloc] init];
detailVC.messageText = messageTextField.text;
}
for DetailVC.h
NSString *messageText;
#property (nonatomic, copy) NSString *messageText;
for DetailVC.m
#synthesize messageText;
- (void)viewLoad
{
testLabel.text = messageText;
}
testLabel is the UILabel inside my DetailVC.
You can simply create property on another viewController. Suppose your textField is on view1 and you want to send it on view2 then:
in view 2
.h file
#interface view2:UIViewController {
NSString *str;
}
#property (nonatomic, retain) NSString *str;
in .m file
#synthesize str;
Now you can send your text from view1 to view 2 like:
objView2.str = txtField.text;
For viewing one textfield's text in another use
secondTextField.text = firstTextField.text;
Hope this helped let me know if you are looking for something different.
take one variable in the app delegate like in appdelegate.h
#interface appdelegate
{
NSString *str1;
}
#property (nonatomic, retain) NSString *str;
In .m file synthesize it.
set the text after editing the textfield(app del.str=textfield.text i.e setting value).And use the same wherever you want.
NSString *str = appdel.str(getting value);
Try this one:
#interface SecondView:UIViewController
{
NSString *stringSecond;
}
#property(nonatomic, retain) NSString *str;
In First View u have to create an reference like this:
#import "SecondView.h"
SecondView *detailViewController = [[SecondView alloc] initWithNibName:#"SecondView" bundle:nil];
detailViewController.stringSecond = #"Some string";
when i select a cell in my modified picker view, a blue background colour appears.
all other treads i have seen do not give me a good answer.
anyone has a solution?
pickerView.showsSelectionIndicator = NO;
Just set the UITableViewCell selectionStyle property to UITableViewCellEditingStyleNone
cell.selectionStyle = UITableViewCellEditingStyleNone;
I have add toolbar at the top of picker view and add cutom button as a sub view of toolbar and both picker view and toolbar are add as a subview of Main view so you can handle this.
I've met this one. Let's get a look at it in details. To create your custom picker view, you create your custom UIView class, e.g. :
#interface TimeAroundView : UIView
{
NSString *title;
UIImage *image;
}
#property (nonatomic, retain) NSString *title;
#property (nonatomic, retain) UIImage *image;
#end
Then in your custom picker view controller you create some container, e.g. NSArray, which will get all TimeAroundView objects you want to represent in your picker view. So, for every object you must do
timeAroundViewObject.userInteractionEnabled = NO;
I think -(id)init is the best place for filling that container in, so you get something like this:
- (id)init
{
self = [super init];
if (self) {
// create the data source for this custom picker
NSMutableArray *viewArray = [[NSMutableArray alloc] init];
TimeAroundView *earlyMorningView = [[TimeAroundView alloc] initWithFrame:CGRectZero];
earlyMorningView.title = #"Early Morning";
earlyMorningView.image = [UIImage imageNamed:#"12-6AM.png"];
earlyMorningView.userInteractionEnabled = NO;
[viewArray addObject:earlyMorningView];
[earlyMorningView release];
TimeAroundView *lateMorningView = [[TimeAroundView alloc] initWithFrame:CGRectZero];
lateMorningView.title = #"Late Morning";
lateMorningView.image = [UIImage imageNamed:#"6-12AM.png"];
lateMorningView.userInteractionEnabled = NO;
[viewArray addObject:lateMorningView];
[lateMorningView release];
// .... (more of objects)
self.customPickerArray = viewArray;
[viewArray release];
}
return self;
}
And in your pickerView:viewForRow:forComponent:reusingView: you just return proper element from array.
That works for me.
When the app is in one view controller, I want to add a view to simulate that data is being loaded when I click my tab bar controller to open another view controller.
Example: When I the app is in the recorder-view, I want it to show a loading view (a view with a activity indicator) when I change to the list of recorded files (which can take some time to load). I've tried manipulate this with the viewWillDisappear-event, but I can't get it to work - the view is not being added before after the viewDidAppear-event occurs.
Anyone have any thoughts regarding this?
Thanks
Thank you for your reply. I tried doing like tou suggested, but I still can't get it to show when I want. I try to set hidden = NO in my viewWillDisappear-event, but it does not show before that view controller disappears and the next one appears
Right now it sounds like you have a UITabBarController That takes up the whole screen. What I would do is put the loading view above the TabBarController and hide it when not necessary. I would create a subclass of loadingViewController in the same xib your tab bar controller came from (or programatically if you desire) and set it to an IBOutlet of the App Delegate.
Something like this:
//In your App Delegate
- (void)applicationDidFinishLaunching:(UIApplication *)application {
[window addSubview:tabBarController.view];
loadingView.hidden = YES;
[window insertSubview:loadingViewController.view aboveSubview:abBarController.view];
[window makeKeyAndVisible];
}
//In your loading View Controller
- (void) setLoadingViewHidden:(BOOL)hidden {
self.view.hidden = hidden;
self.activityIndicator.animating = hidden;
}
The way I've done this in the past is to have a content view which houses either an activity view or the view proper.
In the view controller's nib, instead of adding subviews to the main view, leave it empty and create a new view (such as a table view in the example below) for the view proper.
Also create an activity view (with a threaded progress indicator or somesuch) and a "no results" view.
Then derive your controller class from the something like the following:
//
// ContainerViewController.h
//
#import <UIKit/UIKit.h>
#interface ContainerViewController : UIViewController
{
UIView *myContainerView;
UITableView *myTableView;
UIView *mySearchActivityView;
UIView *myZeroResultsView;
UIView *myCurrentlyShowingView;
}
#property (retain, nonatomic) IBOutlet UIView *containerView;
#property (retain, nonatomic) IBOutlet UITableView *tableView;
#property (retain, nonatomic) IBOutlet UIView *searchActivityView;
#property (retain, nonatomic) IBOutlet UIView *zeroResultsView;
#property (assign) UIView *currentlyShowingView;
#end
//
// ContainerViewController.m
//
#import "ContainerViewController.h"
#implementation ContainerViewController
#synthesize containerView = myContainerView;
#synthesize tableView = myTableView;
#synthesize searchActivityView = mySearchActivityView;
#synthesize zeroResultsView = myZeroResultsView;
- (void)dealloc
{
[myContainerView release], myContainerView = nil;
[myTableView release], myTableView = nil;
[mySearchActivityView release], mySearchActivityView = nil;
[myZeroResultsView release], myZeroResultsView = nil;
myCurrentlyShowingView = nil;
[super dealloc];
}
- (void)viewDidLoad
{
[super viewDidLoad];
self.currentlyShowingView = mySearchActivityView;
mySearchActivityView.backgroundColor = [UIColor clearColor];
myZeroResultsView.backgroundColor = [UIColor clearColor];
}
- (void)setCurrentlyShowingView:(UIView *)view
{
[myCurrentlyShowingView removeFromSuperview];
CGRect frame = view.frame;
frame.size = myContainerView.frame.size;
view.frame = frame;
[myContainerView addSubview:view];
myCurrentlyShowingView = view;
if (view == myTableView)
[myTableView reloadData];
}
- (UIView *)currentlyShowingView
{
return myCurrentlyShowingView;
}
#end
And in the -viewDidLoad method of the derived class, set off the (asynchronous) query:
- (void)viewDidLoad
{
[super viewDidLoad];
myQueryLoader = [[QueryLoader alloc] initWithQuery:#"whatever" delegate:self];
self.currentlyShowingView = mySearchActivityView;
}
and in the delegate callback:
- (void)queryLoader:(QueryLoader *)queryLoader didEndWithResults:(id)results error:(NSError *)error
{
myItems = [results retain];
if (myItems)
self.currentlyShowingView = myTableView;
else
self.currentlyShowingView = myZeroResultsView;
}
Hope this helps!