I am a beginner of iOS and I am writing some practice code in which I am trying to pass a string from one tab to another in a UITabViewController and using a label to display it in the next tab. Now the code where I am passing the message is:
-(IBAction)sendMessage:(id)sender
{
MessageRecepientViewController * contoller = [self.tabBarController.viewControllers objectAtIndex:1];
[contoller passString:_textField.text];
self.tabBarController.selectedIndex = 1;
}
And I am receiving the text here (in the second view controller) as:
-(void) passString:(NSString *) str
{
_string = str;
}
And in viewDidAppear, i am doing this:
- (void) viewDidAppear:(BOOL)animated
{
self.textLabel.text = [NSString stringWithString:_string];
NSLog(#"did appear called, str = %# and label text = %#", _string, self.textLabel.text);
}
and the log is showing that the value of the string is the passed text as it should be, but the value of textLabel.text is always null.
I have tried everything I could think of from checking that the UILabel is attached to the textLabel outlet to writing the code in viewWillAppear and viewDidLoad but nothing have worked so far. The string is showing the correct value but the label is not updating. What is wrong here?
Ok found the error:
It was a minor typo: I had declared IBOutlet as:
IBOutlet UILabel * textlabel;
and property as:
#property (nonatomic, strong) UILabel * textLabel;
and had attached the outlet to textlabel and had been updating textLabel. Fixed this and things are fine!
Related
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.
I have got some UILabels which have been declared as property and synthesized. I am hiding those labels in viewDidLoad. After some calculations, when I try to unhide them using hidden property, app crashes with error mentioned in the subject. I tried NSLog to know if it has been deallocated or not, but it is showing me fine values of labels. Please can someone help me that where is memory management problem while I am accessing it normally. Thanks.
Showing some code for reference:
In .h file:
#interface abc : UIViewController{
UILabel *value;
}
#property(nonatomic,retain) IBOutlet UILabel *value;
In .m file:
#synthesize value;
-(void) viewDidLoad
{
value.hidden = YES;
}
-(IBAction) calculate:(id)sender
//On some button click, assign some value to label and unhide it
NSLog(#"%#",value); //perfectly OK
value.hidden = NO; //throws exception here
}
The error is because the label is getting released and getting assigned to NSString. Check how are you setting value to the label. You should be assigning an NSString to UILabel which causes it to throw this error when hidden property is called on value param.
I am creating an iphone app, and I am using a UITextField. In my textfield, if the user fills the textfield, I would still like the user to see what they are text. I am not using the keyboard to fill the textfield - the values are getting filled in from buttons on a calculator. It there a way to make the textfield show the most recently entered values as it normally would with the keyboard?
Thanks.
Here is the code that populates the textfield:
- (IBAction)number:(id)sender {
NSString *entry = [sender currentTitle];
NSLog(#"%#", entry);
if(justOpenedCalculator){
total.text = #"";
total.text = [total.text stringByAppendingString:entry];
addFirstValueToDiscount = YES;
}else{
total.text = [total.text stringByAppendingString:entry];
addFirstValueToDiscount = YES;
}
justOpenedCalculator = NO;
}
I don't see why you could not do it with the textField. Just go over the UITextFieldDelegate methods in the Apple Documentation, and implement it. Here is the LINK !. You need to implement that and instead of doing a justOpenedCalculator you could utilize the textFieldDidBeginEditing method, and other delegate methods for your functions.
Make sure that you do a yourTextField.inputView = yourCustomKeyboard.
Make a
#property (nonatomic, retain) IBOutlet UITextField ...
And just assign the value to your textfield.
So, I want to place a label in my fist view and place in a second one a UISwitch.
But the problem is I can't link together everything.. :/
in my first view i have that
- (void)onRoff {
if (mySwitch1.on) {
test.hidden = YES;
}
else (test.hidden = NO);
}
but here I have an error with mySwitch1 because it's declared in my secondView..
I don't know if it's clear, I want to link a label and a switch in different view..
Thanks !
Indeed you are not very clear. The first thing you might want to try is describe what you did:
how are your two views instantiated?
Let's assume your two views are instantiated from two different nib files.
what is the object you want to have access to your label and switch?
Let's assume it's a view controller. It's a bit unusual for a single view controller to control two views from two different nib files, but after all, why not?
In any case, you can set the owner class for your two nib files to be the class of your view controller. Then in Interface Builder, from the first view, you can bind the label to the file owner's UILabel outlet. And in Interface Builder, from the second view, you can bind the UISwitch to the file owner's second outlet, of type UISwitch.
But perhaps the onRoff methods of yours is actually a method of one of your two view class? The same idea apply: you can set the file owner in the second nib file to be the view class of the first view, and then bind the switch to the file owner's UISwitch outlet.
But it sounds like your design might be worth working on...
Edit: after your comment, here is a bit more...
The problem is that your two view controllers each control a different page and have no reason to know about each other. So you need a middle man object. That could be another controller. Let's use the Application delegate. Then, in the IBAction method of your SwitchViewController, you can do something like:
- (IBAction) switchChangedValue:(UISwitch *) sender {
NSString *newLabelText = sender.isOn ? #"On" : #"Off";
self.labelViewController.label.text = newLabelText;
}
Now how will everybody know about each other? First each view controller will inform the middle man. Here is it for the SwitchViewController:
- (void) viewDidLoad
{
[super viewDidLoad];
MyAppDelegate *appDelegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
appDelegate.switchViewController = self;
}
Second, the app delegate will need to coordinate everything:
#interface MyAppDelegate : …
#property (nonatomic, retain) SwitchViewController *switchViewController;
#property (nonatomic, retain) LabelViewController *labelViewController;
#end
#implementation MyAppDelegate
#synthesize switchViewController = _switchViewController;
#synthesize labelViewController = _labelViewController;
- (void) setSwitchViewController:(SwitchViewController *) newSwitchController {
if (newSwitchController != _switchViewController) {
[_switchViewController release];
_switchViewController = [newSwitchController retain];
_switchViewController.labelViewController = _labelViewController;
if (_labelViewController)
_labelViewController.label.text = _switchViewController.switch.isOn ? #"On" : #"Off";
}
}
- (void) setLabelViewController:(LabelViewController *) newLabelController {
if (newLabelController != _labelViewController) {
[_labelViewController release];
_labelViewController = [newLabelController retain];
_labelViewController.switchViewController = _switchViewController;
if (_switchViewController)
_labelViewController.label.text = _switchViewController.switch.isOn ? #"On" : #"Off";
}
}
I left out a number of details, but I hope the big picture is clear.
So you have declared ur UISwitch in the second view and ur label in the first view. All u have to do is just use NSUserDefaults to achieve wat u want. Have the following method in the second view itself. Dont bring it to the first view.
- (void)onRoff {
if (mySwitch1.on) {
[[NSUserDefaults standarduserdefaults]setObject:#"off" forKey:#"state"];
[[NSUserDefaults standarduserdefaults]synchronize];
}
else {
[[NSUserDefaults standarduserdefaults]setObject:#"on" forKey:#"state"];
[[NSUserDefaults standarduserdefaults]synchronize];
}
}
Now in the viewWillAppear method of the first view just chk the value of the NSUserDefaults..
-(void)chkState{
NSString *tempStr=[[NSUserDefaults standarduserdefaults]objectForKey:#"state"];
if([tempStr isEqualTo:#"on"]) {
test.hidden=YES;
}
else {
test.hidden=NO;
}
}
Call this method in the viewWillAppear of the firstview like this....
[self chkState];
Hope this helps....If u want save the state of the switch too then just chk the userdefaults value again in the viewWilAppear method of the 2nd view and based
I'm new to Objective-C and iPhone SDK development. I want to call a method in the same class:
- (void) setFilePath:(NSString *) p
{
[self methodCall];
}
- (void) methodCall
{
fileContent.text = #"Test"; //fileContent is a UITextView
}
If the property "filePath" is set, the method "setFilePath" is called. Then the UITextView, created in IB, should display the text. But that doesn't work ...
If I call the method directly via button in IB, then the UITextView changes his content successfully:
- (IBAction) clickButton
{
fileContent.text = #"Test";
}
What could be the problem?
Thanks for your answers!
EDIT 2: I solved the problem by setting "filePath" after pushing the view:
- (IBAction) showFileContent {
FileContentsViewController *fileContentsViewController = [[FileContentsViewController alloc] init];
[self.navigationController pushViewController:fileContentsViewController animated:YES];
fileContentsViewController.filePath = self.filePath;
fileContentsViewController.title = [NSString stringWithFormat:#"Content from von %#", [filePath lastPathComponent]];
[fileContentsViewController release];
}
EDIT 1: Here's the code of my interface:
#interface FileContentsViewController : UIViewController {
NSString *filePath;
UITextView *fileContent;
}
- (void) methodCall;
#property (nonatomic, retain) NSString *filePath;
#property (nonatomic, retain) IBOutlet UITextView *fileContent;
#end
... and here's the code of the implementation:
#import "FileContentsViewController.h"
#implementation FileContentsViewController
#synthesize filePath;
#synthesize fileContent;
- (void) setFilePath:(NSString *) p
{
NSLog(#"setFilePath executed!");
[self methodCall];
}
- (void) methodCall
{
fileContent.text = #"Test"; // UITextView
}
// some standard methods
#end
... and finally the code of the method that sets "filePath":
- (IBAction) showFileContent {
FileContentsViewController *fileContentsViewController = [[FileContentsViewController alloc] init];
fileContentsViewController.filePath = self.filePath;
fileContentsViewController.title = [NSString stringWithFormat:#"Content from von %#", [filePath lastPathComponent]];
[self.navigationController pushViewController:fileContentsViewController animated:YES];
[fileContentsViewController release];
}
What it looks like is that the fileContentsViewController created in -showFileContent doesn't have anything assigned to its FileContentsViewController.fileContent (or, at least, fileContent doesn't point to a UITextView that gets displayed) when fileContentsViewController.filePath is set.
You set filePath immediately after creating fileContentsViewController. If FileContentsViewController's -init doesn't create an appropriate fileContent, then when -setFilePath: is called from -showFileContent, there's no fileContent to set the text of. If fileContentsViewController is a typical view controller, fileContent won't exist until fileContentsViewController is loaded, which (I believe) happens during -pushViewController:animated.
One fix is to override -setFileContent to set fileContent.text as appropriate:
-(void)setFileContent:(UITextView*)fileContentView {
if (fileContent != fileContentView) {
[fileContent release];
fileContent = [fileContentView retain];
if (self.filePath) { // if file path is not nil
fileContent.text = ...;
}
}
}
Another other fix is to ensure you only set filePath when fileContent exists, but this is more brittle. A third is to set filePath after you push fileContentsViewController.
The way you would discover the cause during debugging is to check two things: execution ("Is the code I'm expecting to be executed ever reached?") and data ("Do the variables hold the values I expect?"). Set breakpoints in -showFileContent and -methodCall so you know that the methods are being called (which would be one reason for failure). If execution makes it into -methodCall, the problem must be something else. From there, examine the values of the variables used in -methodCall and you'll discover fileContent is either nil or not the same fileContent that shows up later.
Have you checked that fileContent has been set up at the time setFilePath is called? If you're trying to set things up at start up then it's possible that you're making calls before the views have been loaded (which the OS delays until the last possible moment).
You can force views to load by calling [self view] just before you try to access any of your Interface Builder views (NB don't call loadView - that doesn't do what you'd think).
If the problem is that setFilePath: is not called that I would guess that your code looks like
filePath = #"some value";
when it should be
self.filePath = #"some value";
When using #property you need to use self.filePath to call the methods, otherwise you will just access the ivar directly.
How have you define filePath property ?
I think that it is the problem...