Given the following UITableViewController, why can't I get any of the UISearchBarDelegate methods to be called? I'm omitting the UITableViewDelegate and UITableViewDataSource methods.
#import <UIKit/UIKit.h>
#interface OpportunitySearchViewController : UITableViewController <UISearchBarDelegate>
#end
#import "OpportunitySearchViewController.h"
#interface OpportunitySearchViewController ()
#end
#implementation OpportunitySearchViewController
- (id)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder:aDecoder];
if (self) {
NSLog(#"initWithCoder:");
};
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"self=%# self.view=%# ", self, [self view]);
}
- (void)viewDidUnload {
[super viewDidUnload];
NSLog(#"viewDidUnload");
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
NSLog(#"shouldAutorotateToInterfaceOrientation:");
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#pragma mark - UISearchBarDelegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText {
NSLog(#"searchBar:textDidChange:");
}
#end
I've confirmed that my Storyboard scene is configured to use the OpportunitySearchViewContoller class and I've confirmed that the UISearchBar on the scene has the First Responder set as it's delegate. Although that might be wrong, but I couldn't find a File's Owner in the Storyboard interface.
Help would be appreciated.
Don't connect the first responder to your class as the delegate. Drag from the search bar to the controller object itself and make that the connection to the delegate.
Related
In my app i've both tabbar and navigationBar. rootview controller tabbar and tabbar has 4 navigation controller.
I want to make some viewcontrollers to be portrait only. It may be a common question but I've tried enough but I could not solve this.
How to make portrait orientation for some view Controller?
I've solved this problem and answering so that if someone face same problem they can get a help.
shouldAutorotate, supportedInterfaceOrientations, preferredInterfaceOrientationForPresentation
The above methods don't get called of a viewcontroller if they are inside any tabbarcontroller of navigationcontroller. If these methods are declared inside tabbarcontroller or navigation controller then they will get called. In my case the viewcontrollers was inside navigationcontroller and the navigation controllers are inside a tabbarcontroller.
For solving this I make a class FixedOrientationTab, it is a subclass of UITabBarController, and a navigation class OrientationEnabledNavigation, it is a subclass of UINavigationController. Then I implemented shouldAutorotate, supportedInterfaceOrientations, preferredInterfaceOrientationForPresentation methods inside FixedOrientationTab and OrientationEnabledNavigation.
OrientationEnabledNavigation.h
#import <UIKit/UIKit.h>
#interface OrientationEnabledNavigation : UINavigationController
#end
OrientationEnabledNavigation.m
#import "OrientationEnabledNavigation.h"
#interface OrientationEnabledNavigation ()
#end
#implementation OrientationEnabledNavigation
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (BOOL)shouldAutorotate
{
return [self.topViewController shouldAutorotate];
// return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.topViewController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.topViewController preferredInterfaceOrientationForPresentation];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
FixedOrientationTab.h
#import <UIKit/UIKit.h>
#interface FixedOrientationTab : UITabBarController
#end
FixedOrientationTab.m
#import "FixedOrientationTab.h"
#interface FixedOrientationTab ()
#end
#implementation FixedOrientationTab
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (BOOL)shouldAutorotate
{
return [self.selectedViewController shouldAutorotate];
// return NO;
}
- (NSUInteger)supportedInterfaceOrientations
{
return [self.selectedViewController supportedInterfaceOrientations];
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation
{
return [self.selectedViewController preferredInterfaceOrientationForPresentation];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Then if you want to use navigation controller in your project then use OrientationEnabledNavigation and for tabbar FixedOrientationTab. After that if you implement shouldAutorotate, supportedInterfaceOrientations, preferredInterfaceOrientationForPresentation these method inside your viewcontroller then they will get called.
Hope this helps.. :)
In my code, when I set canDisplayBannerAds=YES on my view controller, I get callbacks to viewDidLayoutSubviews when the ad disappears but not when the ad appears. I'm guessing this is because Apple moves the original self.view of the view controller to self.originalContentView when you set canDisplayBannerAds to YES.
My question is, what is a reasonable work around for this?
My solution to this problem is to replace self.view before setting canDisplayBannerAds=YES with a UIView that overrides layoutSubviews.
#protocol LayoutViewDelegate <NSObject>
- (void) layout;
#end
#interface LayoutView : UIView
#property (nonatomic, weak) id<LayoutViewDelegate> delegate;
#end
#implementation LayoutView
- (void) layoutSubviews {
[super layoutSubviews];
if (self.delegate) [self.delegate layout];
}
#end
I do this replacement in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"Calendar.viewDidLoad");
// Replace the view, before setting up ads for iOS7, so we can get callbacks for viewDidLayoutSubviews; otherwise, we only get viewDidLayoutSubviews callbacks when ad disappears.
if ([Utilities ios7OrLater]) {
self.layoutView = [[LayoutView alloc] initWithFrame:self.view.frame];
self.view = self.layoutView;
self.layoutView.delegate = self;
}
}
And in viewDidAppear, I do:
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
if ([Utilities ios7OrLater]) {
self.canDisplayBannerAds = YES;
}
}
And I add the delegate method:
// This *always* gets called when the banner ad appears or disappears.
#pragma - LayoutViewDelegate method
- (void) layout {
// do useful stuff here
}
#pragma -
I have a storyboard with 3 view controllers: QuestionsTableViewController, QuestionViewController and AnswerViewController
For all intensive purposes, QuestionsTableViewController is basically my main menu. it has a selection of topics which when selected populate a question label in QuestionViewController which is then segued to.
The user enters his/her answer in a UITextField and hits a submit button causing a modal segue to the AnswerViewController which has a label that returns either a correct or incorrect message to the user based on a comparison of their answer to the coded correct answer. This final View Controller also has a button (back to menu) that when clicked should take the user back to the QuestionsTableViewController (i.e. my menu).
This last part (the returning to the menu) is where I am having problems.
I can dismiss the AnswerViewController multiple ways, but I cant figure out what I need to do to dismiss the QuestionViewController as part of this same button press.
I am including snipets of my QuestionViewController and AnswerViewController classes below.
QuestionViewController.m
#import "QuestionViewController.h"
#import "AnswerViewController.h"
#interface QuestionViewController ()
#end
#implementation QuestionViewController
#synthesize currentQuestionDisplay;
#synthesize userAnswerTextField;
#synthesize currentQuestion;
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
AnswerViewController *avc = [segue destinationViewController];
[avc setCurrentQuestion:currentQuestion];
[avc setUserAnswer:[userAnswerTextField text]];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.currentQuestionDisplay setText:[currentQuestion question]];
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[self setCurrentQuestionDisplay:nil];
[self setUserAnswerTextField:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)dismissKeyboard:(id)sender {
[userAnswerTextField resignFirstResponder];
}
- (void)dimissThisVC
{
[self dismissViewControllerAnimated:YES completion:^(void){}];
}
#end
AnswerViewController.m
#import "AnswerViewController.h"
#import "QuestionViewController.h"
#interface AnswerViewController ()
#end
#implementation AnswerViewController
#synthesize displayCurrentAnswer;
#synthesize currentQuestion;
#synthesize userAnswer;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if([userAnswer isEqualToString:currentQuestion.answer]) {
[self.displayCurrentAnswer setText:#"You are correct!"];
}
else {
[self.displayCurrentAnswer setText:#"You are wrong!"];
}
// Do any additional setup after loading the view.
}
- (void)viewDidUnload
{
[self setDisplayCurrentAnswer:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
- (IBAction)dismissAnswerVC:(id)sender {
[[self presentingViewController]
dismissViewControllerAnimated:YES
completion:^(void){ }];
}
#end
When you dismiss the modal view, in the completion block have this code:
[self.navigationController popViewControllerAnimated:YES];
Or if you want to go to the top most controller:
[self.navigationController popToRootViewControllerAnimated:YES];
in an effort to complete this post for others who may reference it, i am reposting user523234's answer here:
In the prepareForSegue method, you missed this line:
avc.delegate = self;
hopefully this can help someone else who has fallen into the same hole that i was in.
I'm new to iOS Dev, I'm following the Stanford CS193P classes for Fall 2010. I'm on assignment 3 and I'm setting my delegate to my view and by using the debugger I'm noticing the call to my delegate method won't happen, I don't understand what could be happening. My code is as follows:
GraphViewController.h:
#interface GraphViewController : UIViewController <GraphViewDelegate> {
GraphView *graphView;
float scale;
}
#property (retain) IBOutlet GraphView *graphView;
#property float scale;
- (IBAction)zoomIn;
- (IBAction)zoomOut;
#end
GraphViewController.m:
#implementation GraphViewController
#synthesize graphView, scale;
- (NSString *)functionForGraph:(GraphView *)requestor {
NSLog(#"%#", #"culo peluo");
return #"lol";
}
- (float)scaleForGraph:(GraphView *)requestor {
return self.scale;
}
- (IBAction)zoomIn {
}
- (IBAction)zoomOut {
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
self.graphView.delegate = self;
self.scale = 20;
[self.graphView setNeedsDisplay];
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
#end
GraphView.h:
#class GraphView;
#protocol GraphViewDelegate
- (NSString *)functionForGraph:(GraphView *)requestor;
- (float)scaleForGraph:(GraphView *)requestor;
#end
#interface GraphView : UIView {
id <GraphViewDelegate> delegate;
}
#property (assign) id <GraphViewDelegate> delegate;
#end
GraphView.m:
#implementation GraphView
#synthesize delegate;
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
// Initialization code
}
return self;
}
- (void)drawRect:(CGRect)rect
{
CGFloat cgScale = [self.delegate scaleForGraph:self];
[AxesDrawer drawAxesInRect:self.bounds originAtPoint:self.center scale:cgScale];
}
- (void)dealloc
{
[super dealloc];
}
#end
Put a break point on the line where you set the graph view's delegate.
Inspect the graphView variable. Is it nil?
This happens to me all the time and it's always (well nearly always) because I have failed to connect the outlet to the view in interface builder.
Let's say class YourClass is a delegate for some other class. And delegate methods are not called, despite that delegate property is set up.
Most probably the problem is that your class instance, that is a delegate for your other class is released before the delegate method is called on it. Make it more persistent by making this class a property or instance variable of other class or by using dispatch_once. For example,
Change
YourClass *instance = [[YourClass alloc] init];
by
#property(nonatomic, strong) YourClass *instance;
self.instance = [[YourClass alloc] init];
This problem occurs because in ARC everything that is created inside a method (and is not an instance variable) is released, when method finishes. And delegate methods cannot be called, that are invoked by some background process.
I've written a big blog post on this problem. This is pretty common situation.
http://alwawee.com/wordpress/2013/07/31/on-xmppframework-delegate-method-not-being-called/
Ive got a few pointers for ya on this one:
You don't need an iVar (internal Variable) if you have the variable as a property, it will still work, I've never know it not to.
GraphView
#interface GraphView : UIView {
}
#property (assign) id <GraphViewDelegate> delegate;
#end
GraphViewController
#interface GraphViewController : UIViewController <GraphViewDelegate> {
}
#property (retain) IBOutlet GraphView *graphView;
#property float scale;
- (IBAction)zoomIn;
- (IBAction)zoomOut;
#end
You need to set your delegate in your view to be able to use it.
GraphViewController
#implementation GraphViewController
( ... )
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.delegate = self;
}
return self;
}
( ... )
#end
You are not calling the delegate functions anywhere in your GraphView.m. Try testing it out by placing this piece of code in your - (id)initWithFrame:(CGRect)frame method, right before you return.
[self.delegate functionForGraph:nil];
and see if it logs any message to the console.
Of course this is just to test the delegate implementation, you should actually be using this delegate call in some other method in your GraphView.m which is able to process your requestor
In my nib, I have a UITextView component.
In my UIViewController I have a UITextView member field and I have used IB to make sure that the two are connected (at least I think I did that by dragging from "Files Owner" and dropping it on the UITextView in IB and selecting my member variable).
Now, when I update the text via setText:, the UITextView still remains blank.
When I break into my code, the member variable (called textView) is nil.
So I am guessing I have not used IB correctly. How can I make sure that this variable is connected to the UITextView graphic element?
Here is the code
// My interface looks like
#import <UIKit/UIKit.h>
#interface DetailsController : UIViewController
{
UITextView *textView;
}
#property (nonatomic, retain) IBOutlet UITextView *textView;
#end;
// and the implementation
#import "DetailsController.h"
#implementation DetailsController
#synthesize textView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self)
{
// Custom initialization
}
return self;
}
- (void)dealloc
{
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
// Releases the view if it doesn't have a superview.
[super didReceiveMemoryWarning];
// Release any cached data, images, etc that aren't in use.
}
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
}
- (void)viewDidUnload
{
[super viewDidUnload];
// Release any retained subviews of the main view.
// e.g. self.myOutlet = nil;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Return YES for supported orientations
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
// used pressed the "Done" button
- (IBAction)done
{
[self dismissModalViewControllerAnimated:YES];
}
- (void)setDetails: (NSString *)detail withQuote:(NSString *)quote
{
NSLog(#"%#", textView);
[textView setText:detail];
}
#end
save nib file after connecting outlet, build project and run, it should work if it's connected
I can't see agere you are calling setText, but I think that you try to do it in the initializer. GUI code should not be done before the viewDidLoad in the case of using XIB's or loadView if you make your GUI programatically, or the other viewWill/viewDid... methods.
The reason is because the views are not loaded before they are actually needed, it is called lazy loading. You should Google that for more info.