Change UILabel Text from UiViewController in another UIViewController - ios

Okay it seems like I have made some mistakes and I did not get it with pointer and initializations by now...
Here is the problem :
I have a UIViewController for a registration process called : RegisterViewController
It calls a method in its ViewDidLoad :
[self performSelector:#selector(activateUsernamePopover) withObject:nil afterDelay:0.1];
This method looks like this :
- (void) activateUsernamePopover {
PopoverViewController *popcontroller = [[PopoverViewController alloc] init];
popcontroller.title = nil;
[popcontroller setPopoverText:#"Test"];
FPPopoverController *popover = [[FPPopoverController alloc] initWithViewController:popcontroller];
popover.arrowDirection = FPPopoverArrowDirectionUp;
popover.border = NO;
popover.tint = MgoGreyTint;
[popover setShadowsHidden:true];
[popover presentPopoverFromView:_usernameInput]; }
This will made a Popover visible. This works great.
But I Do have a few more TextFields where I want to show a Popover with a different text.
So I made a method in the PopoverViewController called setPopoverText :
- (void)setPopoverText:(NSString *)text {
[_popoverLabel setText:text];
[_popoverLabel setNeedsDisplay]; }
I call it in my activateUsernamePopover method :
[popcontroller setPopoverText:#"Test"];
And there is the problem.
I can log the text in the PopoverViewControllers method setPopoverText its fine.
But it did not change the text. I logged the _popoverLabel like this :
NSLog(#"%#",_popoverLabel);
and its (null).
I know there is some issue with the pointer or the instance of PopoverViewController I am working with, but objective c is not that clear to me yet.
Anyone got some answers for me ?
How can I change the Text of that UILabel ?
I also could imagine giving the Text to the Controller while instancing it.
Something like that :
PopoverViewController *popcontroller = [[PopoverViewController alloc] initWithPopoverText:#"Test"];
But I don´t know how. I don´t need to change the Text while the popover is visible. It will be released when the user taps in the TextField or elsewhere.
Thanks so far.

Since the UILabel is not created yet when you call init method. the way to do it is to keep text in the NSString property.
In you PopoverViewController, create the init method like this
#interface ViewController : UIViewController
- (id)initWithPopoverText:(NSString *)text;
#end
In the implementation file, keep hold of the text in the property and on viewDidLoad, you could set the text to the label.
#interface PopoverViewController ()
#property (nonatomic) NSString *popoverText;
#end
#implement PopoverViewController
- (id)initWithPopoverText:(NSString *)text {
self = [super init];
if (self) {
_popoverText = text;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
//set label.text here
self.popoverLabel.text = self.popoverText;
}
#end

Related

Creating an instance for other class

I have no idea how I should correctly name the title but I know exactly what my problem is (I will eventually edit the title later).
I am pretty new to Objective-C and I am still learning.
So, I have a class that contains a tableView (I will call it ClassA) and another with a normal UIView (ClassB). What I want to do, is to let a button appear when a row is selected.
I created in my ClassB.h file:
+(id)sharedInstance;
#property (retain, nonatomic) IBOutlet UIButton *btn;
-(void) showBtn :(BOOL) show;
And in my ClassB.m file:
#synthesize btn;
static ClassB *this = nil;
(+id) sharedInstance {
if(!this) {
#synchronized (self) {
this = [[ClassB alloc] init];
}
}
return this;
}
-(void)viewDidLoad {
[self showBtn:NO] //because I only want to let it appear when a row is selected.
[self.view addSubview:btn];
}
-(void) showBtn :(BOOL) show { // I called this method in classA.
if (show == NO) {
btn.hidden = YES;
} else {
btn.hidden = NO;
}
}
So when I launch my app, the button is hidden and stays hidden when I select a row. I debugged, and found that btn is nil when I called the method in ClassA. After some research, I found that the method is called for another instance, so here my question, what can I do, to get it called for the right instance?
EDIT
Here part of my ClassA.m
- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSInteger row = [indexPath row];
[[ClassB sharedInstance] showBtn:YES];
}
Observation: The ClassB is a UIViewController which is wrong. UIViewControllers have viewDidLoad.
Implementation Suggestion:
The correct implementation for the requirement would be that you create a custom cell with a button. Hide the button in awakeFromNib method. in didSelectRowAtIndex set the cell.button.isHidden = YES.
This should alone take care of the requirement mentioned above.

Override Custom UITableView Class Method

I am using MWPhotoBrowser to display some photos in an app and I would like for example to change the title of the navigation controller. With a value I have in my current view controller. From the current view controller I modally call MWPhotoBrowser like this
MWPhotoBrowser *browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
//Tried this below didn't work
browser.title = #"MY NEW TITLE";
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:browser];
nc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:nc animated:YES completion:nil];
So I went into the actually files of this class and in MWPhotoBrowser.m there is a function like this
- (void)updateNavigation {
NSUInteger numberOfPhotos = [self numberOfPhotos];
self.title = [NSString stringWithFormat:#"%lu Photots", photosText];
}
And I could just change it manually (hard code a value) there but I want the value to change depending on my original view controller, so I want to pass it a value to be able to set it on my original view controller. So I tried something like this, below updateNavigation I put
-(void)updateTitle:(NSString*)title {
self.title = title;
}
And then in my original view controller I tried
MWPhotoBrowser *browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
[browser updateTitle:#"TEST TITLE"];
But this didn't work either, so how can I set the title of the MWPhotoBrowser form my current view controller, without hard coding a value?
Thanks
updateNavigation can be called anywhere after you called your updateTitle: method, so thats why it didn't work. Also, changing/adding something to external libraries is a bad idea, because when you udpate them you have to remember to apply all your changes again.
Now the easiest way to achieve what you want would be to create a simple subclass of MWPhotoBrowser, something like this :
CustomTitlePhotoBrowser.h
#import <MWPhotoBrowser/MWPhotoBrowser.h> //I'm not sure if this is a correct import, change accordingly
#interface CustomTitlePhotoBrowser : MWPhotoBrowser
-(void)updateTitle:(NSString *)title;
#end
CustomTitlePhotoBrowser.m
#import "CustomBrowser.h"
#interface CustomTitlePhotoBrowser()
#property(nonatomic, copy) NSString *customTitle;
#end
#implementation CustomTitlePhotoBrowser
-(void)updateTitle:(NSString *)title {
self.customTitle = title;
[self updateNavigation];
}
-(void)updateNavigation {
self.title = self.customTitle;
}
#end
And to use it :
CustomTitlePhotoBrowser *browser = [[CustomTitlePhotoBrowser alloc] initWithDelegate:self];
[browser updateTitle:#"TEST TITLE"];
There are two things added in the subclass :
We add a stored property customTitle, so that whenever updateNavigation is called, we still remember what we want to show. I also decided to call [self updateNavigation] here - this may not be needed, but gives you a possibility to change the title while the browser is shown.
We override updateNavigation - this is the clue of all of this. When using CustomTitlePhotoBrowser, whenever the original code calls updateNavigation, our overriden implementation will be called instead.

Calling method from another class doesn't work properly

I am trying to change the text and the position of a UILabel from another class.
I have successfully managed to call my -changeLabel method, which is in my FirstViewController class, from my SecondViewController class. Here is the code I have used in my two classes:
SecondViewController:
#import "FirstViewController.h"
#interface SecondViewController ()
#property (nonatomic,strong) FirstViewController *firstViewController;
#end
#implementation SecondViewController
#synthesize firstViewController;
- (IBAction)button:(id)sender {
firstViewController = [[FirstViewController alloc] init];
[firstViewController changeLabel];
}
FirstViewController:
- (void)changeLabel {
NSLog(#"changeLabel is called!");
label.text = #"New text.";
label.frame = CGRectMake(10, 100, 150, 40);
NSLog(#"%#", label.text);
NSLog(#"%f", label.frame.size.width);
}
The weird thing is that the logger looks like this after pressing the "button" that calls the method:
"2013-12-30 19:24:50.303 MyApp[655:70b] changeLabel is called!"
"2013-12-30 19:24:50.305 MyApp[655:70b] New text."
"2013-12-30 19:24:50.308 MyApp[655:70b] 0.000000"
So it seems the label text change, but it doesn't show up on the screen. And the label width is logged as 0.0.. even though I just set it to 150.
Why is this happening? Am I not able to change frame variables from another class? Is there another way to do this?
IMPORTANT:
As the FirstViewController is the main view controller while the SecondViewController is a side menu, similar to the facebook app:
I want to be able to press a "button" on the SecondViewController(side menu) and call a method in the FirstViewController(main) that changes the position(frame) of a UILabel.
EDIT:
Here is how I created the UILabel:
label = [[UILabel alloc] init];
label.frame = CGRectMake(0, 0, 150, 40);
label.text = #"Text."
[self.view addSubview:label];
I think problem is this. You are calling method from new instance of FirstViewController.
Let assume
1. FirstViewController at stack[0].
2. SecondViewController at stack[1].
If you are navigating or moving from
FirstViewController->SecondViewController
In this case FirstViewController already in memory with some address 0x23ffff.
And in SecondViewController you are again creating new instance of FirstViewController which is point to another address '0x234jurhu`
- (IBAction)button:(id)sender {
firstViewController = [[FirstViewController alloc] init];
[firstViewController changeLabel];
}
Don't create new instance here.
You can use delegate or NSNotification concept for this.
How are you displaying FirstViewController?
Here is the issue:
firstViewController = [[FirstViewController alloc] init];
[firstViewController changeLabel];
You creating a new instance of FirstViewController and updating the label text. If your using these VC's in a navigation stack and you pop back to FirstViewController from SecondViewController, you won't see any label change because they are different instances of the class.
If your using FirstViewController as a childViewController of SecondViewController (with naming of them I don't think this what your doing), then in the - (IBAction)button:(id)sender method you don't need to instantiate a new instance of FirstViewController on each button press.
I have figured out a way to do this thanks to "#Gaurav Wadhwani" answer on this question: call method from other class (self issue).
I added this code in my FirstViewController.h:
+ (FirstViewController *)singletonInstance;
And then added this code in my FirstViewController.m
static FirstViewController *_singletonInstance = nil;
+(FirstViewController*)singletonInstance
{
#synchronized([FirstViewController class])
{
if (!_singletonInstance)
_singletonInstance = [[self alloc] init];
return _singletonInstance;
}
return nil;
}
+(id)alloc
{
#synchronized([FirstViewController class])
{
NSAssert(_singletonInstance == nil, #"Attempted to allocate a second instance of a singleton.");
_singletonInstance = [super alloc];
return _singletonInstance;
}
return nil;
}
Then I added this code in my SecondViewController to run the changeLabel method:
[[FirstViewController singletonInstance] changeLabel];
And that seems to work just fine so far. I hope it wont cause any other "problems" in the future, but right now it seems to be perfect.
Try doing this:
[label setNeedsDisplay];
After the last line in changeLabel.

Passing NSString from one class to another. (ECSlidingViewController?)

Firstly, I've already tried to search for solutions online but none works for me and I'm thinking since I'm using ECSlidingViewController to navigate around the app, I can't utilise the prepareForSegue method thus, my problem may need a different approach.
I have a class called viewInits which holds properties in the .h file that I want allow other classes to set and get it's values. In this case, the property is an NSString *navBarTitle.
In ClassA, I have a tableView:didSelectRowAtIndexPath: method, where I
Create an ViewInits class object - *viewInits.
I then set the setNavBarTitle: to the value of [self.MenuRowsArray objectAtIndex:indexPath.row].
In the next line, I did an NSLog to check and yes, viewInits.navBarTitle now holds the value I desire.
In ClassB's viewDidloadMethod, similarly, I created a ViewInits object - *viewInits and did an NSLog check for viewInits.navBarTitle. But it returns (null). What seems to be the problem here?
Here is the code for how I'm trying to pass the NSString. What am I doing wrong?
viewInit .h
#interface ViewInits : NSObject
#property (strong, nonatomic) NSString *navBarTitle;
#end
ClassA.m tableView:didSelectRowAtIndexPath: method:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *identifier = [self.MenuRowsArray objectAtIndex:indexPath.row];
UIViewController *newTopViewController = [self.storyboard instantiateViewControllerWithIdentifier:identifier];
// *---------- Assign identifier to NSString viewInits ----------*
ViewInits *viewInits = [[ViewInits alloc] init];
[viewInits setNavBarTitle:identifier];
NSLog(#"%#", viewInits.navBarTitle);
// *---------- Assign identifier to NSString viewInits ----------*
[self.slidingViewController anchorTopViewOffScreenTo:ECRight animations:nil onComplete:^
{
CGRect frame = self.slidingViewController.topViewController.view.frame;
self.slidingViewController.topViewController = newTopViewController;
self.slidingViewController.topViewController.view.frame = frame;
[self.slidingViewController resetTopView];
}];
}
ClassB.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
// *========== ECSlidingViewController ==========*
self.view.layer.shadowOpacity = 0.75f;
self.view.layer.shadowRadius = 10.0f;
self.view.layer.shadowColor = [UIColor blackColor].CGColor;
if (![self.slidingViewController.underLeftViewController isKindOfClass:[MenuViewController class]])
{
self.slidingViewController.underLeftViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
}
[self.view addGestureRecognizer:self.slidingViewController.panGesture];
// *========== ECSlidingViewController ==========*
ViewInits *viewInits = [[ViewInits alloc] init]; // Create ViewInit class object
self.navBar.topItem.title = viewInits.navBarTitle;
NSLog(#"%#", viewInits.navBarTitle); // <<--- This always ends up null. What's wrong?
}
Your help are much appreciated. Thank you.
If you want to use ViewInit as a common store of settings it should be a singleton so that all other instances in the app can get it. Currently you're creating a new instance each time you want to use it, so the new instance doesn't have any of your previous settings.
Aside, I know what the sliding view controller is, I ask about it because you may be using it incorrectly. If you have a view controller which is the current top view controller and it changes the top view controller (class A might be doing this, not sure) then the reference self.slidingViewController will stop working part way through your code.

iOS - passing Sender (button) name to addSubview

I have a main view with 3 buttons. Clicking on any of the buttons adds a SubView.
The buttons have different titles and are all linked to IBAction "switchView"
The "switchView" code is below.
- (IBAction)switchView:(id)sender{
secondView *myViewController = [[secondView alloc] initWithNibName:#"secondView" bundle:nil];
[self.view addSubview:myViewController.view];
}
The "secondView" loads up correctly and everything works well.
The problem is I want to be able to know which button was the Sender.
I don't want to create 3 subviews, one for each button. The code and XIB would be absolutely the same>
The only difference would be a variable that I would like to set up in the second view (viewDidLoad method) depending on who is the Sender (which button was clicked)
Is this possible? Or I would need to create 3 subViews - one for each button?
Your help is greatly appreciated!
You can identify different buttons with the tag property.
e.g. with your method:
-(IBAction)switchView:(id)sender {
UIButton *button = (UIButton*)sender;
if (button.tag == 1) {
//TODO: Code here...
} else if (button.tag == 2) {
//TODO: Code here...
} else {
//TODO: Code here...
}
}
The tag property can be set via the InterfaceBuilder.
Hope this helps.
I think you can solve in 2 ways:
Create a property like:
#property (nonatomic, strong) IBOutlet UIButton *button1, *button2, *button3;
in your viewcontroller and link the buttons to them as referencing outlet on the XIB.
Give a different tag to each button on your xib and ask for the tag of the sender with UIButton *b=(UIButton*)sender; b.tag; like Markus posted in detail.
Solving my problem it all came down to transferring data between the mainView and subView.
In my mainView.h I declared an NSString and its #property
...
NSString *btnPressed;
}
#property(nonatomic, retain) NSString *btnPressed;
...
then in my mainView.m inside the switchView method I did this:
- (IBAction)switchView:(id)sender{
secondView *myViewController = [[secondView alloc] initWithNibName:#"secondView" bundle:nil];
btnPressed = [NSString stringWithFormat:#"%i", [sender tag]];
[myViewController setBtnPressed:self.btnPressed];
[self.view addSubview:myViewController.view];
}
This line in the code above actually takes care of transferring the data to the newly created subView:
[myViewController setBtnPressed:self.btnPressed];
Then in my secondView.h I declare exactly the same NSString *btnPressed and its #property (though this a completely different object than the one declared in main)
Then in my secondView.m I get the value of the button pressed I'm interested in.
- (void)viewDidLoad {
[super viewDidLoad];
int theValueOfTheButtonPressed = [self.btnPressed intValue];
}
This works well.
Don't forget to #synthesize btnPressed; as well as [btnPressed release]; in both mainView.m and secondView.m

Resources