I'm using storyboard for an iOS application, my storyboard looks like this: http://d.pr/7yAY (droplr url)
The problem is when I click the login button, I send the username captured to the events table view controller. To do that I use prepareForSegue function, but apparently when I try to set the username in throws an exception.
My code is as follows:
ViewController.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
- (IBAction) logintButton:(id)sender;
#property (weak, nonatomic) IBOutlet UITextField *username_tf; // textfield
#end
ViewController.m
#import "ViewController.h"
#import "EventsTableViewController.h"
#interface ViewController ()
#end
#implementation ViewController
#synthesize username_tf;
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"ToMainApp"])
{
EventsTableViewController * dest = (EventsTableViewController *)[segue destinationViewController];
NSString * username = [[NSString alloc] initWithFormat:#"%#", username_tf.text];
[dest setUsername:username];
}
}
- (IBAction) logintButton:(id)sender
{
//NSLog(#"Logint button pressed");
[self performSegueWithIdentifier:#"ToMainApp" sender:sender];
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidUnload
{
[self setUsername_tf:nil];
[super viewDidUnload];
// Release any retained subviews of the main view.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
}
EventsTableViewController.h
#import <UIKit/UIKit.h>
#interface EventsTableViewController : UITableViewController
{
NSString * username;
}
#property (nonatomic, retain) NSString * username;
#end
EventsTableViewController.m
#import "EventsTableViewController.h"
#interface EventsTableViewController ()
#end
#implementation EventsTableViewController
#synthesize username;
- (id)initWithStyle:(UITableViewStyle)style
{
self = [super initWithStyle:style];
if (self) {
// Custom initialization
}
return self;
}
...
#end
The throwed exception is:
2012-03-15 14:19:27.304 StoryboardAssistance[30989:f803]
-[UINavigationController setUsername:]: unrecognized selector sent to instance 0x68abf60 2012-03-15 14:19:27.306
StoryboardAssistance[30989:f803] *** Terminating app due to uncaught
exception 'NSInvalidArgumentException', reason:
'-[UINavigationController setUsername:]: unrecognized selector sent to
instance 0x68abf60'
*** First throw call stack: (0x13c9022 0x155acd6 0x13cacbd 0x132fed0 0x132fcb2 0x28e6 0x43e4be 0xdb5ab 0x2974 0x13cae99 0x1614e 0x160e6
0xbcade 0xbcfa7 0xbc266 0x3b3c0 0x3b5e6 0x21dc4 0x15634 0x12b3ef5
0x139d195 0x1301ff2 0x13008da 0x12ffd84 0x12ffc9b 0x12b27d8 0x12b288a
0x13626 0x253d 0x24a5) terminate called throwing an exception(lldb)
Any suggestions?
Your segue's destination view controller is your Navigation Controller, not your Events Table View controller.
You can get the Events controller by accessing the Navigation controller's topViewController property.
Try this:
UINavigationController *navController = (UINavigationController*)[segue destinationViewController];
EventsTableViewController *eventsController = [navController topViewController];
NSString * username = [[NSString alloc] initWithFormat:#"%#", username_tf.text];
[eventsController setUsername:username];
Alternatively, try this:-
(It does the same as jonkroll's answer but in one line and removes the warning "Incompatible pointer types initializing 'ViewController *__strong' with an expression of type UIViewController *"
NameOfViewController *vc = (NameOfViewController *)[[segue destinationViewController] topViewController];
Another thing to verify is that you have properly assigned your destination ViewController as the proper class in Interface Builder. By default this will be UIViewController or UITableViewController etc. If you have a custom class with getters/setters, you need to remember to change the class in the Interface Builder to reflect accordingly, otherwise you will receive an invalid selector error message.
Related
I've problems passing data to a new view controller.
I've two VC. In the "FirstVC" there is a table view with dynamic prototypes cells. The generic cell contains a label and a button and it's assigned to its own class "GenericCell". I want to pass to the SecondVC the text of the cell label when I press the button, but the app crashes with errors:
Unknown class _TtC13testTableView37SecondVC in Interface Builder file.
UIViewController setMyString:]: unrecognized selector sent to instance 0x7fa05e418110
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIViewController setMyString:]: unrecognized selector sent to instance 0x7fc8add05710
I tried:
To use the segue (with prepareForSegue method) outside the getText method
1a. Pushing the VC from the outside of the getText method
Implementing and calling set/get method of myString
Adding attributes to myString property
but the app crashes the same.
GenericCell.h
#import <UIKit/UIKit.h>
#protocol MyCellDelegate
-(void)getText:(NSString *)text;
#end
#interface GenericCell: UITableViewCell
#property (weak, nonatomic) IBOutlet UILabel * label;
#property (assign, nonatomic) id <MyCellDelegate> delegate;
#end
GenericCell.m
#import "GenericCell.h"
#interface GenericCell()
#end
#implementation GenericCell
- (IBAction)buttonPressed {
if (self.delegate) {
[self.delegate getText:self.label.text];
}
}
#end
FirstVC.m
#import "FirstVC.h"
#import "GenericCell.h"
#import "SecondVC.h"
#interface FirstVC() <UITableViewDataSource,UITableViewDelegate, MyCellDelegate>
#property (weak, nonatomic) IBOutlet UITableView *tableView;
#property NSString * idToPass;
#end
#implementation FirstVC
NSMutableArray<NSString *> *array;
- (void)viewDidLoad {
array = [[NSMutableArray alloc]initWithObjects:#"0x22", #"0x11", #"0x24", nil];
[super viewDidLoad];
self.tableView.dataSource=self;
self.tableView.delegate=self;
self.tableView.rowHeight=100;
}
-(void)getText:(NSString *)text {
self.idToPass = text;
SecondVC * secondVC = [self.storyboard instantiateViewControllerWithIdentifier:#"SecondVC"];
secondVC.myString = self.idToPass;
[[self navigationController] pushViewController:secondVC animated:YES];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return array.count;
}
- (GenericCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
GenericCell * cell = [[self tableView]dequeueReusableCellWithIdentifier:#"GenericCell" forIndexPath:indexPath];
cell.delegate = self;
cell.label.text = [array objectAtIndex:indexPath.row];
return cell;
}
#end
SecondVC.h
#import <UIKit/UIKit.h>
#interface SecondVC : UIViewController
#property (weak, nonatomic) IBOutlet UILabel *label;
#property NSString * myString;
#end
SecondVC.m
#import "SecondVC.h"
#interface SecondVC ()
#end
#implementation SecondVC
- (void)viewDidLoad {
self.label.text = self.myString;
[super viewDidLoad];
}
#end
The "idToPass" is set correctly with delegation.
This work for me: in the buttonPressed method update the if statement like this
if ([self.delegate respondsToSelector:#selector(getText:)]){
[self.delegate getText:self.label.text];
}
Another option to give SecondVC the data is using
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
SecondVC * vc = segue.destinationViewController;
if ([segue.identifier isEqualToString: #"yourSegue"]) {
vc.myString = self.idToPass;
}
}
A tip I suggest is to check (with a simple if statement) if your object in SecondVC is nil or !nil
I hope this help :)
In getText method you assign text to myProperty instead myString...
It should be:
secondVC.myString = self.idToPass;
I have a viewcontroller that has a uitableview being populated by my core data model. I am trying to set this up so I can tap on an item in the uitableview, have that item pass to a uitextfield on a second viewcontroller, where it can be edited and then saved back to my core data model.
prepare for segue
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"EditItemSegue"])
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:sender];
Item *item = [[self fetchedResultsController]objectAtIndexPath:indexPath];
[segue.destinationViewController setItemname:[item valueForKey:#"itemname"]];
}
}
error
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[EditItem setItemname:]: unrecognized selector sent to instance
Im pretty sure the error indicates that i am trying to perform an action on an object that isnt allowed.
Some help . push in the right direction would be appreciated.
edititem.h
#import "ViewController.h"
#interface EditItem : ViewController
#property (strong, nonatomic) IBOutlet UITextField *editItemField;
#property (nonatomic, strong) NSString *toDoItemName;
#end
edititem.m
#import "EditItem.h"
#interface EditItem ()
#end
#implementation EditItem
#synthesize editItemField;
#synthesize toDoItemName;
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
editItemField.text = toDoItemName;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
edit
This is what I tried in my viewWillLoad
- (void)viewWillAppear:(BOOL)animated
{
[editItemField setText:toDoItemName];
}
You're calling setItemname: when you should be calling setToDoItemName:.
I have this Segue here:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([[segue identifier] isEqualToString:#"showDetail"]) {
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
//NSDate *object = self.objects[indexPath.row];
NSString *strPOIndex = [self.tableData[indexPath.row] valueForKey:#"POIndex"];
LHPurchaseOrderDetail *controller = (LHPurchaseOrderDetail *)[[segue destinationViewController] topViewController];
[controller setDetailItem:strPOIndex];
controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
controller.navigationItem.leftItemsSupplementBackButton = YES;
}
}
and what I am trying to do with it is pass strPOIndex to setDetailItem in my detail controller from my master controller.. but when I run this, I get an error:
-[LHPurchaseOrderMaster setDetailItem:]: unrecognized selector sent to instance 0x156cce80
I dont understand why this is happening, is it an issue with my storyboard? or my master controller or detail controller? Here is my Detail Controller:
.h:
#import <UIKit/UIKit.h>
#interface LHPurchaseOrderDetail : UIViewController
#property (strong, nonatomic) IBOutlet UINavigationBar *NavBar;
#property (strong, nonatomic) id detailItem;
#property (weak, nonatomic) IBOutlet UILabel *detailDescriptionLabel;
#end
.m:
#import "LHPurchaseOrderDetail.h"
#interface LHPurchaseOrderDetail ()
#end
#implementation LHPurchaseOrderDetail
- (void)setDetailItem:(id)newDetailItem {
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
- (void)configureView {
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = [self.detailItem description];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
[self configureView];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
Master Controller:
.h
#import <UIKit/UIKit.h>
#import "ShinobiDataSource.h"
#import "PopupGenerator.h"
#class LHPurchaseOrderDetail;
#interface LHPurchaseOrderMaster : UITableViewController<UIPopoverControllerDelegate, UIPickerViewDelegate>
#property (strong, nonatomic) IBOutlet UIButton *communityBtn;
#property (strong, nonatomic) IBOutlet UIButton *lotBtn;
#property (strong, nonatomic) IBOutlet UIButton *goBtn;
- (IBAction)communityBtnPressed:(id)sender;
- (IBAction)lotBtnPressed:(id)sender;
- (IBAction)goBtnPressed:(id)sender;
#property(nonatomic, retain) NSArray * tableData;
#property (strong, nonatomic) LHPurchaseOrderDetail *purchaseOrderController;
#end
Your error is this:
-[LHPurchaseOrderMaster setDetailItem:]: unrecognized selector sent to instance 0x156cce80
so it seems that somewhere in your LHPurchaseOrderMaster class you're trying to access and set the detailItem property as if it would be a part of LHPurchaseOrderMaster but because it doesn't exist there, you get an unrecognized selector error.
Edit
You should check for three things:
In Interface Builder check that the segue from LHPurchaseOrderMaster ViewController is to an UINavigationController that embeds the LHPurchaseOrderDetail ViewController as the first view controller in its stack.
Check the Class name returned by [segue destinationViewController]topViewController] like this:
id obj = [segue destinationViewController]topViewController];
NSLog(#"%#", NSStringFromClass([obj class]));
The class name should be LHPurchaseOrderDetail. If it's not, then you have a problem in your Storyboard where more than certainly you've connected the segue wrong.
Check your LHPurchaseOrderMaster class for any code that tries to access the "detailItem" property as if it would be part of this class.
It seems that the property you are trying to access is not accessible (wrong retrieved object).
Have you tried to use instead of
LHPurchaseOrderDetail *controller = (LHPurchaseOrderDetail *)[[segue destinationViewController] topViewController];
Something like
LHPurchaseOrderDetail *controller = (LHPurchaseOrderDetail *)[[segue destinationViewController] viewControllers][0];
I had sometimes the same your issue.
Set your detailItem not to NSString. Not to id. The problem is here,
self.detailDescriptionLabel.text = [self.detailItem description];
In configureView method change the code as follow,
- (void)configureView {
// Update the user interface for the detail item.
if (self.detailItem) {
self.detailDescriptionLabel.text = self.detailItem;
}
}
Don't forget to change this as well,
- (void)setDetailItem:(NSString *)newDetailItem {
if (_detailItem != newDetailItem) {
_detailItem = newDetailItem;
// Update the view.
[self configureView];
}
}
I have a view controller on the StoryBoard with my custom class. Here the code:
BGMDatePickerViewController.h
#import <UIKit/UIKit.h>
//declare a protocol with name
#protocol DatePickerViewControllerDelegate //declare a delegate so that this class can notify another class when a user selects a chart
//protocol methods
//- (void)userDataChangedWithUsername;
#end
//declare a class with inheritance
#interface BGMDatePickerViewController : UIViewController <UIPickerViewDelegate, UIPickerViewDataSource, UITextFieldDelegate>
//create a public property
#property (weak, nonatomic) id<DatePickerViewControllerDelegate> delegate; //property to store the delegate
#end
I would like to show this ViewController on another one with delegate. Here the code:
BGMChartViewController.h
#import <UIKit/UIKit.h>
#import "BGMDatePickerViewController.h"
//declare a class with inheritance
#interface BGMChartViewController : UIViewController <UIActionSheetDelegate, DatePickerViewControllerDelegate> //conforms UIActionSheetDelegate and my custom DatePickerViewControllerDelegate protocols
//create a public IB methods
- (IBAction)showDateEntryForm:(id)sender;
#end
BGMChartViewController.m
#import "BGMChartViewController.h"
#interface BGMChartViewController ()
//create a private properties
#property (strong, nonatomic) UIPopoverController *datePickerPopover;
#end
#implementation BGMChartViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:NO];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
- (IBAction)showDateEntryForm:(id)sender
{
DDLogVerbose(#"%s: has been started...", __FUNCTION__);
BGMDatePickerViewController *datePickerVC = [self.storyboard instantiateViewControllerWithIdentifier:#"dateEntryFormVC"];
datePickerVC.delegate = self; //HERE THE FALL!!!!!
self.datePickerPopover = [[UIPopoverController alloc] initWithContentViewController:datePickerVC];
//define the popover size
self.datePickerPopover.popoverContentSize = CGSizeMake(320.0, 400.0);
//let’s display it
[self.datePickerPopover presentPopoverFromRect:[(UIButton *)sender frame]
inView:self.view
permittedArrowDirections:UIPopoverArrowDirectionAny
animated:YES];
}
#end
On the line which I marked it just fall with:
-[BGMDatePickerViewController setDelegate:]: unrecognized selector sent to instance 0x78a3bcf0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[BGMDatePickerViewController setDelegate:]: unrecognized selector sent to instance 0x78a3bcf0'
If I comment this problem line it's ok I see my custom view controller so that means that I am ok with instantiateViewControllerWithIdentifier tag...
I don't understand what do I do wrong?
Modify to the below line and check:-
#protocol DatePickerViewControllerDelegate<NSObject>
I am getting an error that I can't seem to solve:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException',
reason: '-[UICollectionViewController setSearchString:]: unrecognized
selector sent to instance 0x7fcd4b655930'
The error comes when I call a prepareForSegue method:
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString *searchStringToPass = [[NSString alloc]initWithFormat:_inputField.text];
UINavigationController *navController = [segue destinationViewController];
ResultsCollectionViewController *rvc = (ResultsCollectionViewController *)([navController viewControllers][0]);
NSLog(#"Search String to Pass is: %#", searchStringToPass);
//[rvc setSearchString:searchStringToPass];
rvc.searchString = searchStringToPass;
//userViewController.user = [self.users objectInListAtIndex:[self.tableView indexPathForSelectedRow].row];
}
The ViewController that I am trying to get to is imbedded in a navigation controller. The code for it is:
#import "ResultsCollectionViewController.h"
#interface ResultsCollectionViewController ()
//#property(nonatomic, weak) IBOutlet UICollectionView *collectionView;
#property(strong, nonatomic) NSArray *flickrPhotos;
#end
#implementation ResultsCollectionViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
NSLog(#"search string is %#",_searchString);
}
-(void)getFlickrPhotosWithSearchString:(NSString*)searchString{
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
And the .h file is:
#import "BaseViewController.h"
#interface ResultsCollectionViewController : BaseViewController <UICollectionViewDataSource, UICollectionViewDelegateFlowLayout>
#property (strong, nonatomic) NSString *searchString;
#end
Anybody have any idea what the issue is? Many thanks in advance.
You report the following error message:
-[UICollectionViewController setSearchString:]: unrecognized selector sent to instance 0x7fcd4b655930
Note that the "unrecognized selector" in the error message is the setter accessor method for your searchString property, but the class referenced is the standard UICollectionVieController, not your custom class.
That suggests that you neglected to specify the base class for the destination scene in Interface Builder. The storyboard has therefore instantiated a standard UICollectionViewController rather than your custom class, and thus your searchString accessor methods are not found.