MyViewController has one UIButton and another MainViewController use MyViewController.
but MainViewController can't change UIButton title in MyViewController.
also, in MyViewController only change UIButton title in viewDidLoad method.
What's wrong?
MyViewController
#interface MyViewcontroller : UIViewController {
IBOutlet UIButton *imageButton;
}
#property (nonatomic, retain) UIButton *imageButton;
#implementation MyViewcontroller : UIViewController {
#synthesize imageButton;
- (void)viewDidLoad { // can change button title
[imageButton setTitle:#"buttonTitle" forState:UIControlStateNormal]
}
- (void)setButtonTitle { // can't change button title
[imageButton setTitle:#"buttonTitle" forState:UIControlStateNormal];
}
}
MainViewController
#implementation MainViewController : UIViewController {
#synthesize scrollView;
- (void)viewDidLoad { // can't change button title
MyViewcontroller *myView = [[MyViewcontroller alloc] initWithNibName:#"MyViewcontroller" bundle:nil];
[myView.imageButton setTitle:#"ddd" forState:UIControlStateNormal];
[scrollView addSubview:myView.view];
[myView release], myView = nil;
}
}
It happens because the outlets don't get wired until after the view is loaded, and the view doesn't get loaded until after it gets called for the first time (it's lazy loading). You can fix this very easily by just ensuring that you always load the view first. However, you might want to reconsider your design and make the button title dependent on some other item that's not part of the view hierarchy.
For example, if you re-order your calls, it will work:
MyViewcontroller *myView = [[MyViewcontroller alloc] initWithNibName:#"MyViewcontroller" bundle:nil];
[scrollView addSubview:myView.view]; // view is loaded
[myView.imageButton setTitle:#"ddd" forState:UIControlStateNormal]; // imageButton is now wired
Related
I'm developing the iPhone app. I custom defined the titleview for navigation bar. The title view contains a button, I also defined the delegate method to support the button click event. But when the button clicked, the delegate cannot be executed. I am not sure why ?
Below as my codes:
UPDelegate.h
#protocol UPDelegate <NSObject>
#optional
-(void)buttonClick;
#end
TitleView.h
#import <UIKit/UIKit.h>
#import "UPDelegate.h"
#interface TitleView :UIView
#property (nonatomic, unsafe_unretained) id<UPDelegate> delegate;
-(id)initWithCustomTitleView;
#end
TitleView.m
#synthesize delegate;
-(id)initWithCustomTitleView
{
self = [super init];
if (self) {
UIButton *titleButton = [UIButton buttonWithType:UIBUttonTypeCustom];
titleButton.frame = CGRectMake(0, 0, 20, 44);
[titleButton setTitle:#"ABC" forState:UIControlStateNormal];
// add action
[titleButton addTarget:delegate action:#selector(buttonClick) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:titleButton];
}
return self;
}
In my ViewController, i implement the protocal as below:
MyViewController.h
#interface MyViewController : UIViewController<UPDelegate>
and in the .m file, i wrote the delegate method, but cannot be exeucte.
MyViewController.m
-(void)buttonClick{
NSLog("click title button");
}
You have to set your delegate, from you code sample you are creating id<UPDelegate> delegate; in your titleView class.
So in your MyViewController where you have added <UPDelegate>, create an instance of TitleView and set delegate to self.
So in your MyViewController use:
TitleView*titleView=[[TitleView alloc]init];
titleView.delegate=self;
It sounds like you have not set the value of your titleView's delegate property, so any messages sent to the delegate property are ignored because the delegate is nil.
You should make sure that you are setting your titleView's delegate to be your MyViewController. The best place to do this is most likely in your MyViewController's viewDidLoad: method.
Did you set the delegate anywhere? Because you have to set the delegate of your TitleView to MyViewController:
titleView.delegate = self;
I subclassed my navigation bar, making the title view clickable. When clicked, it will present another view controller. I am creating a protocol in the navigation bar, that will tell the navigation controller that the title view has been clicked. Here is how my navigation bar is defined:
NavigationBar.h:
#protocol NavigationBarDelegate;
#interface NavigationBar : UINavigationBar
{
id <NavigationBarDelegate> delegate;
BOOL _titleClicked;
}
#property (nonatomic, assign) id <NavigationBarDelegate> delegate;
#end
#protocol NavigationBarDelegate
#optional
- (void)titleButtonClicked:(BOOL)titleClicked;
#end
The delegate implements one optional method. The .m file is as follows:
NavigationBar.m:
#implementation NavigationBar
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
_titleClicked = 0;
}
return self;
}
- (void)drawRect:(CGRect)rect
{
self.tintColor = [UIColor colorWithRed:(111/255.f) green:(158/255.f) blue:(54/255.f) alpha:(255/255.f)];
UIImage *image = [UIImage imageNamed:#"titlelogo.png"];
UIButton *titleButton = [[UIButton alloc] initWithFrame:CGRectMake(0, 0, image.size.width, image.size.height)];
titleButton.backgroundColor = [UIColor colorWithPatternImage:image];
[titleButton addTarget:self action:#selector(titleButton:) forControlEvents:UIControlEventTouchUpInside];
// self.navigationController.delegate = self;
[self.topItem setTitleView:titleButton];
[super drawRect:rect];
}
- (void)titleButton:(UIButton *)sender
{
_titleClicked = !_titleClicked;
[self.delegate titleButtonClicked:_titleClicked];
}
This creates a navbar with a logo and calls the titleButton method when the title button has been clicked. Everything is fine up till here and the navigation bar displays nicely.
In my RootViewController:
NavigationBar *navigationBar = [[NavigationBar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.view.frame.size.width, 44.0f)];
navigationBar.delegate = self;
[self.navigationController setValue:navigationBar forKey:#"navigationBar"];
An implementation of titleButtonClicked is also there. When I click on the title view however, I get the following error: -[UINavigationController titleButtonClicked:]: unrecognized selector sent to instance
Why am I getting titleButtonClicked sent to UINavigationController? Is there something I need to do in my navigation controller? I am just using plain old UINavigationController. Do I need to subclass that too? If so, why?
EDIT:
Calling po self.delegate on line [self.delegate titleViewClicked:_titleClicked]; in NavigationBar.m yields the result below. How did the delegate change its type? How can I fix that?
(lldb) po self.delegate
(objc_object *) $1 = 0x07550170 <UINavigationController: 0x7550170>
As #idz said, the problem is with your:
#property (nonatomic, assign) delegete;
Don't you see that it's weird that you don't even have a:
#synthesize delegete;
That's because UINavigationBar already defines a delegate variable as idz said.
change your declaration to:
// use unsafe_unretained in ARC, not assign
#property (nonatomic, unsafe_unretained) myDelegete;
and of course
#synthesize myDelegate;
You have a clash/ambiguity between your delegate and UINavigationBar's delegate property. Rename your delegate to disambiguate them.
I have two views in my application: in main view there are input fields that the user must fill and a button connected to the second view. In the second view there is a table view, when the user selects a row automatically returns to the main view.
My problem is that when you return to the main view the values of text fields are cleared.
Any solutions?
Thank you.
Second View header
#class MainViewController;
#interface ListaViewController : UIViewController
<UITableViewDataSource, UITableViewDelegate, UISearchBarDelegate>
{
UITableView *table;
UISearchBar *search;
MainViewController *child;
}
#property (nonatomic, retain) IBOutlet UITableView *table;
#property (nonatomic, retain) IBOutlet UISearchBar *search;
#property (nonatomic, retain) MainViewController *child;
- (IBAction)switchBack:(id)sender;
Second View Implementation:
-(IBAction)switchBack:(id)sender
{
child.selectedCountry = selectedCountry;
child.codiceComune = codiceComune;
[self.navigationController popViewControllerAnimated:YES];
}
First View:
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
cityField.text = selectedCountry;
}
This not work!
-(IBAction)switchBack:(id)sender
{
MainViewController *controller = [[MainViewController alloc] initWithNibName:#"MainViewController" bundle:nil];
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated: YES];
[controller release];
}
It means you create new MainViewController, not return to previous.
Use this code instead
-(IBAction)switchBack:(id)sender
{
[self dismissModalViewControllerAnimated:YES];
}
P.S. It works if you go to the second vievcontroller same way, as you write in -(IBAction)switchBack:(id)sender
As a guess without code, you're probably emptying or initialising your text fields in viewDidLoad, viewDidAppear or viewWillappear - do it in your viewController init instead.
To begin, I would like to apologize for my English :)
I have FirstViewController, which contains scrollView. This is scrolView with enabled paging, and have 2 pages with 2 different view controllers. From one of the view controllers by touching the button the third view controller appears like a modal view. I call a method in FirstViewController that must disable scrolling and hide two labels which is not contained in the scrollView.
Method is executing, but UI not changes, scrolling still enabled and labels still visible.
Now a bit of code:
This is a piece of the FirstViewController.h (not the whole code):
#interface FirstViewController : UIViewController <UIScrollViewDelegate> {
IBOutlet UIScrollView *scrollView;
IBOutlet UILabel *label1;
IBOutlet UILabel *label2;
}
#property (nonatomic, retain) UILabel *label1;
#property (nonatomic, retain) UILabel *label2;
#property (nonatomic, retain) UIScrollView *scrollView;
-(void)prepareToModal;
#end
Now it's -(void)prepareToModal; implementation:
-(void)prepareToModal {
[label1 setHidden:YES];
[label2 setHidden:YES];
scrollView.scrollEnabled = NO;
}
So, from the one of the view controllers, which contained in scrollView, I call prepareToModal
Previously:
#import "FirstViewController.h"
Next:
FirstViewController *vc = [[FirstViewController alloc] init];
[vc prepareToModal];
[vc release];
So, that's all. I put a breakpoint in prepareToModal, and it stopped executing. The method is called, but nothing changes on screen...
What am I doing wrong?
How to do this correctly?
Update:
I solved this problem.
When I present this modal view, I wrote this:
ThirdViewController *tvc = [[ThirdViewControler alloc] init];
tvc.delegate = self;
UINavigationController *nc = [[UINavigationController alloc] initWithRootViewController:tvc];
[self presentModalViewController:nc animated:YES];
[tvc release];
[nc release];
Now, insted of [self presentModalViewController:nc animated:YES]; I write this:
[[[[UIApplication sharedApplication].windows objectAtIndex:0] rootViewController] presentModalViewController:nc animated:YES];
And It's working very well, I don't need a method -(void)prepareToModal;
Thanks a lot :)
Make sure you have hooked up your IBOutlets in Interface Builder.
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!