I am making a login page for an application using Parse.
I get the error "visible #interface for 'UIResponder' declares the selector 'viewDidAppear'"
I also get "visible #interface for 'UIResponder' declares the selector 'presentViewController:animated:present'"
So, in my AppDelegate.m I have:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];//I GET THE ERROR HERE
if (![PFUser currentUser]) { // No user logged in
// Create the log in view controller
PFLogInViewController *logInViewController = [[PFLogInViewController alloc] init];
[logInViewController setDelegate:self]; // Set ourselves as the delegate
// Create the sign up view controller
PFSignUpViewController *signUpViewController = [[PFSignUpViewController alloc] init];
[signUpViewController setDelegate:self]; // Set ourselves as the delegate
// Assign our sign up controller to be displayed from the login controller
[logInViewController setSignUpController:signUpViewController];
// Present the log in view controller
[self presentViewController:logInViewController animated:YES completion:NULL];//I GET THE ERROR HERE
}
}
In my AppDelegate.h:
#import <UIKit/UIKit.h>
#import <Parse/Parse.h>
#interface AppDelegate : UIResponder <UIApplicationDelegate>
#property (strong, nonatomic) UIWindow *window;
#end
// Implement both delegates
#interface DefaultSettingsViewController :
UIViewController <PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate>
#end
How can I go about fixing this issue?
Your superclass needs to be a UIViewController subclass. In your code, it's a UIResponder subclass.
But I think the reason is that you're putting code that should go in a view controller into the app delegate. Move the viewDidAppear: method to the view controller where it needs to be.
Related
I'd like to trigger a message from viewController to another viewController.
And I coded like below, but viewController didn't call delegate.
I want to call delegate without stroyboard. I just want to send a message to another viewController.
viewController2.h
#protocol ViewController2Delegate;
#interface ViewController2 : UIViewController
#property (nonatomic, weak) id<ViewController2Delegate> delegate;
#end
#protocol ViewController2Delegate <NSObject>
- (void)showSomethingByDelegate;
#end
viewController2.m
#import "ViewController2.h"
#interface ViewController2 ()
#end
#implementation ViewController2
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (IBAction)buttonPressed:(id)sender {
[self.delegate showSomethingByDelegate];
}
#end
viewController.m
#import "ViewController.h"
#import "ViewController2.h"
#interface ViewController ()
<ViewController2Delegate>
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
ViewController2 *vc2 = [[ViewController2 alloc] init];
vc2.delegate = self;
}
// Below method was not called by delegate.
- (void)showSomethingByDelegate {
NSLog(#"Button Was Pressed!!!");
}
#end
well let me show an example more simple.
File: firstVC.h
/* This define the protocol object,
you can write methods required or optional the diference is when
the protocol is used in a class, xcode show you a yellow warning with required methods
like UITableViewDelegate, UITextFieldDelegate... */
#protocol firstVCDelegate <NSObject>
#required
- (void)didMessageFromOtherViewController: (NSString *)messageStr;
#optional
- (void)didOtherMessageNotRequired: (NSString *)messageStr;
#end
/* This is the definition of first UIViewController */
#interface firstViewController : UIViewController
#end
/* This is the definition of second UIViewController object with
a property that is our protocol 'firstVCDelegate' */
#interface secondViewController : UIViewController
#property (nonatomic, weak) id <firstVCDelegate> firstVCDelegate;
- (void)executeDelegateProcess;
#end
File: firstVC.m
#import "firstVC.h"
#pragma mark - First UIViewController with delegate
#interface firstViewController() <firstVCDelegate>
#end
#implementation firstViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Creating the 'secondViewController' object with delegate on this class
secondViewController *svc = [secondViewController new];
// Assign the delegate class
[svc setFirstVCDelegate: self];
// Run the delegate logic
[svc executeDelegateProcess];
}
- (void)didMessageFromOtherViewController:(NSString *)messageStr
{
// Receiving the message from the instance of our protocol in the 'secondViewController' class
NSLog(#"MESSAGE #1: %#", messageStr);
}
- (void)didOtherMessageNotRequired:(NSString *)messageStr
{
// Receiving the message in optional method
NSLog(#"MESSAGE #2: %#", messageStr);
}
#end
#pragma mark - Second UIViewController
#implementation secondViewController
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)setFirstVCDelegate:(id<firstVCDelegate>)firstVCDelegate
{
if (firstVCDelegate)
_firstVCDelegate = firstVCDelegate;
}
- (void)executeDelegateProcess
{
// This method is only for demo
// You can execute your delegate in the way you need to use
if (_firstVCDelegate) {
[_firstVCDelegate didMessageFromOtherViewController: #"Hello world, using the required method from secondViewController class"];
[_firstVCDelegate didOtherMessageNotRequired: #"Hello code using the optional method"];
}
}
#end
In your appDelegate.m in the method didFinishLaunchingWithOptions you can put this, and you need to #import "firstVC.h"
self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]];
self.window.autoresizesSubviews = YES;
[self.window makeKeyAndVisible];
[_window setRootViewController: [firstViewController new]];
Execute and see two logs messages, I hope I've helped :)
ViewController2 *vc2 = [[ViewController2 alloc] init];
This line of code is not doing what you think it is, this is creating a NEW instance of ViewController2 and storing it inside the variable vc2. At no point (based on your code) is this variable added to the navigation stack and displayed on screen.
Edit
Also as noticed by Holex, your vc2 variable will be removed from memory after the viewDidLoad is finished as you are not holding onto a reference of it. You would either need to create a property to hold onto it, or push it onto the navigation stack for the navigationController to hold onto it.
There are multiple ways to solve this issue:
Instead of creating a new viewController2, find a reference to the one already displayed on the screen (if it is on the screen).
If its not on the navigation stack, add vc2 to the navigation stack [self.navigationController pushViewController:vc2 animated:YES]; (assuming you have a navigation controller).
If not on the stack, and not intending to use a navigationController, present vc2 modally, such as [self presentViewController:vc2 animated:YES completion:nil];
Delegate declaration
// FolderListViewController.h
#import <UIKit/UIKit.h>
#import "Folder.h"
#protocol FolderSelectionDelegate <NSObject>
#required
- (void)setFolder:(Folder *)folder;
#end
#interface FolderListViewController : UITableViewController
#property (nonatomic, assign) id<FolderSelectionDelegate> delegate;
- (IBAction)showDashboard:(id)sender;
#end
Delegate is called from didSelectRowAtIndexPath:
// FolderListViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.delegate setFolder:dataSource[indexPath.row]];
}
The VC that should be receiving the message
#import <UIKit/UIKit.h>
#import "FolderListViewController.h"
#import "Folder.h"
#interface ProjectListViewController : UITableViewController <FolderSelectionDelegate, UISplitViewControllerDelegate, UISearchBarDelegate, UINavigationControllerDelegate>
#property (nonatomic,retain)UIActivityIndicatorView *activityIndicatorObject;
#property (nonatomic, copy)Folder *folder;
-(void)loadProjects:(Folder*)folder;
#end
Action that presents the VC
- (void)foldersButtonTapped {
UINavigationController *vc = [[UIStoryboard storyboardWithName:#"MainStoryboard_iPhone" bundle:nil] instantiateViewControllerWithIdentifier:#"FolderListNavController"];
vc.delegate = self;
[self presentViewController:vc animated:YES completion:nil];
}
Delegate method implementation
- (void)setFolder:(Folder *)folder {
_folder = folder;
[self loadProjects:folder];
}
I have read through multiple threads on here and haven't had any luck. At first, I didn't have the reference to ProjectListVC setup when presenting the FolderListVC (ie, vc.delegate = self). That doesn't seem to be the problem here though. I am working on an app that was built for iPad and scaling it to work across all devices. The implementation as it is here works (it's setup as a split view controller). Any help would be greatly appreciated
I think that UINavigationcontroller is creating problem as it is not setting the FolderListViewController delegate . Can You try like this.
FolderListViewController *vc=[self.storyboard instantiateViewControllerWithIdentifier:#"FolderListViewController"];
vc.delegate=self; // protocol listener
[self.navigationController pushViewController:vc animated:YES];
I have two view controllers. We'll call them listViewController and mapViewController. The listViewController shows first, a user taps a button that shows the mapViewController. The user taps a button on a annotation which is where my problems start.
When the user taps a button on mapViewController, I would like to call a method listViewController and dismiss mapViewController. To do this I am using this code:
mapViewController.m
listViewController* lvc = [[listViewController alloc] initWithNibName:nil bundle:nil];
[lvc getInformation:StringParameter];
[self dismissViewControllerAnimated:YES completion:nil];
However, when executing getInformation it seems that the listViewController class has been dealloc'd because all of the objects that I initialized in the viewDidLoad on listViewController are now nil including self, which just breaks everything.
I assume I'm creating the listViewController object incorrectly in mapViewController. I've tried it with a nil for nibName with the same result.
Ok, Let me clear one thing. On listViewController, you presentViewController a mapViewcontroller right? And you want invoke getInformation of the instance from mapViewController. In the code you're added, you instantiate listViewController again. You have 2 different instance of listViewController.
One option is to use a delegate pattern:
In your MapViewController.h file:
#protocol MapViewControllerDelegate <NSObject>
-(void)dismissMe;
-(void)getInformation:(NSString *)stringParameter;
#end
#interface MapViewController : UIViewController
#property (weak)id <MapViewControllerDelegate> delegate;
#end
In your MapViewController.m file:
-(void)annotationButtonTap:(id)button
{
[self.delegate getInformation:stringParameter];
[self.delegate dismissMe];
}
In your ListViewController.h
#import "MapViewController.h"
#interface ListViewController : UIViewController <MapViewControllerDelegate>
-(void)dismissMe
{
[self dismissViewControllerAnimated:YES completion:nil];
}
-(void)getInformation:(NSString *)stringParameter
{
//do whatever you plan with stringParameter
}
And somewhere in you ListViewController.m file where you create the MapViewController instance:
mapViewController = [[MapViewController alloc] initWithNibName:#"MapViewController" bundle:nil];
mapViewController.delegate = self; //make sure you do this
In a view, let's call it firstView I created a secondView as follows and pushed it if certain thing happened in the firstView:
SecondViewController *secondVC = [[secondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
[self.navigationController pushViewController:secondVC animated:YES];
[secondVC release];
Now when I'm in the secondView if let say a button is pressed I want to go back to firstView and also pass back a value from secondView to the firstView (let say an integer value of a textfield from secondView to the firstView).
Here is what I tried:
#protocol SecondViewControllerDelegate;
#import <UIKit/UIKit.h>
#import "firstViewController.h"
#interface SecondViewController : UIViewController <UITextFieldDelegate>
{
UITextField *xInput;
id <SecondViewControllerDelegate> delegate;
}
- (IBAction)useXPressed:(UIButton *)sender;
#property (assign) id <SecondViewControllerDelegate> delegate;
#property (retain) IBOutlet UITextField *xInput;
#end
#protocol SecondViewControllerDelegate
- (void)secondViewController:(SecondViewController *)sender xValue:(int)value;
#end
And in the m file
- (IBAction)useXPressed:(UIButton *)sender
{
[self.delegate secondViewController:self xValue:1234]; // 1234 is just for test
}
And then in the firstView I did:
#import "SecondViewController.h"
#interface FirstViewController : UITableViewController <SecondViewControllerDelegate> {
}
#end
And implemented:
- (void) secondViewController:(SecondViewController *)sender xValue:(int)value
{
[self.navigationController popViewControllerAnimated:YES];
}
Now, the problem is for one in FirstViewController I get the warning that "No definition of protocol "SecondViewControllerDelegate" is found, and for two the delegate method (last piece of code above) does not get invoked at all. Can somebody please tell me what's wrong?
After this line
SecondViewController *secondVC = [[secondViewController alloc] initWithNibName:#"SecondViewController" bundle:nil];
Add
secondVC.delegate = self;
Also instead of
- (void) secondViewController:(SecondViewController *)sender xValue:(int)value
{
[self.navigationController popViewControllerAnimated:YES];
}
You should use
- (void) secondViewController:(SecondViewController *)sender xValue:(int)value
{
[sender popViewControllerAnimated:YES];
}
In FirstViewController .h file :
#import "SecondViewController.h"
#interface FirstViewController : UITableViewController <SecondViewControllerDelegate> {
SecondViewController *secondViewController;
}
#end
In implementation file , where you init SecondViewController instance next line assign self to delegate property :
secondViewController.delegate = self;
Next define delegate method :
- (void)secondViewController:(SecondViewController *)sender xValue:(int)value
{
NSLog ("This is a Second View Controller with value %i",value)
}
For problem 1: The #protocol definition for SecondViewControllerDelegate looks like it's in secondViewController.h; are you sure this file is imported in firstViewController.h? Otherwise it won't know about the protocol.
Problem 2: It might be totally unrelated to problem 1. Are you sure the action is hooked up properly? Can you put a NSLog() call in your useXPressed: to make sure that method is actually getting called when you expect it to?
I have the following code pushing a UIViewController. This code is a target method that gets executed when a UIButton is pressed:
-(void)pushNavigationController
{
ParameterListerViewController *plvc = [[ParameterListerViewController alloc] init];
UINavigationController *nvc = [[UINavigationController alloc] initWithRootViewController:plvc];
self.navigationController.navigationBarHidden = YES;
plvc.numberOfParameters = [[numberOfTrialsField text] intValue];
NSLog(#"about to push the navigation controller");
[self.navigationController pushViewController:nvc animated:YES];
}
It gets until the NSLog statement, but after that, the view controller never gets pushed and the app just crashes. Here is the header file of ParameterListerViewController:
ParameterListerViewController.h
-------------------------------
#interface ParameterListerViewController : UIViewController<UITextFieldDelegate>
{
UIScrollView* scrollView;
}
#property(nonatomic) NSInteger numberOfParameters;
#end
Here's the header file which contains the UIButton and the respective target method which contains the code for pushing the navigation controller.
SettingsViewController.h
------------------------
#interface SettingsViewController : UIViewController <UITextFieldDelegate, UIPickerViewDelegate, UITableViewDelegate, UITableViewDataSource>
{
id <SettingsViewDelegate> delegate;
}
#end
And here's the header file of a class object that DOES GET PUSHED:
#interface ItemViewController : UITableViewController
{
}
#end
Any suggestions?
Your nav controller's view has to be in the view hierarchy.
Unless the nav controller is set as the rootViewController of a UIWindow, it needs to be explicitly added.
Try this:
[self.view addSubview:self.nvc.view];
If this is the case, you won't need to do the pushViewController - the plvc will already be visible.