About #selector and MVC - ios

What I have:
four TableViewController(A, B, C, D) - which would show four category
of content.
fake TabBarController based on UITabBarController, it
works fine.
What I want to do:
Add a button on ATableView, and it will use a method on my FakeTabBarController (because I want to share the method so I can use it on BTableViewController, CTableViewController rather than duplicate it two or three times)
So I just make the method public (on the .h file), and included the .h file in my ATableViewController. Then,
addTarget:action:forControlEvents: as always, but.. it doesn't work, please help!
Error:
[ATableViewController assisitantButtonPressed:]: unrecognized selector sent to instance 0x715a8d0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[ATableViewController assisitantButtonPressed:]: unrecognized selector sent to instance 0x715a8d0'
*** First throw call stack:
(0x1ca1012 0x10dee7e 0x1d2c4bd 0x1c90bbc 0x1c9094e 0x10f2705 0x262c0 0x26258 0xe7021 0xe757f 0xe66e8 0x2ea1d3 0x1c69afe 0x1c69a3d 0x1c477c2 0x1c46f44 0x1c46e1b 0x1bfb7e3 0x1bfb668 0x22ffc 0x1c8d 0x1bb5)
libc++abi.dylib: terminate called throwing an exception
FakeTabBarController.h:
#import <UIKit/UIKit.h>
#interface CustomTabBarController : UITabBarController
- (IBAction)assisitantButtonPressed:(UIButton *)sender;
#end
FakeTabBarController.m:
...
- (IBAction)assisitantButtonPressed:(UIButton *)sender
{
switch ([sender tag]) {
case 0: // AA
NSLog(#"AA");
break;
case 1: // BB
NSLog(#"BB");
break;
default:
break;
}
}
...
ATableViewController.m:
#import "ATableViewController.h"
#import "ATableCell.h"
#import "FakeTabBarController.h"
...
- (void)viewDidLoad
{
[super viewDidLoad];
UIImage *AAImage = [UIImage imageNamed:#"search.png"];
UIButton *AAButton = [[UIButton alloc] initWithFrame:CGRectMake(self.view.frame.size.width * 0.73, 0, AAImage.size.width, AAImage.size.height)];
[AAButton setTag:0];
[AAButton setImage:searchImage forState:UIControlStateNormal];
[AAButton addTarget:self action:#selector(assisitantButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:AAButton];
}

This line
[AAButton addTarget:self action:#selector(assisitantButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
sets the target to method assisitantButtonPressed: of self, which is ATableViewController. It throws exception because ATableViewController doesn't have that method. The correct way is to add a weak property to ATableViewController to keep a reference to CustomTabBarController and addTarget to that TabBar, rather than self
#interface ATableViewController
#property (weak, nonatomic) CustomTabBarController* tabBar;
...
#end
#implementation ATableViewController
-(void)viewDidLoad {
[super viewDidLoad];
self.tabBar = <you must somehow obtain the tab bar reference, either here or in init>
...
[AAButton addTarget:self.tabBar action:#selector(assisitantButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
...
}
#end
It's good that you're trying to avoid code duplication. However since ATableViewController, BTableViewController, ... are very similar (judging from your question and their naming), you may want to use just one single TableViewController but with different actual data. Besides, if the method assisitantButtonPressed: really belongs to the table view controller and you moved it to the navBar just to avoid code duplication, it is a very bad practice.

Related

Objective-C UIViewController Category is causing Error NSException

I am using a Category to add functionality to my ViewControllers. When the function from the category is run I get an error unrecognized selector sent to instance 0x7970ebf0. To test out the function I'm calling, I originally had the code within my viewDidLoad where I am calling the added function and it worked fine, so I don't think it is a problem with the function itself. So here is my code for the category and where I call it. Am implementing the Category incorrectly?
Here is "UIViewController+StatusBar.h"
#import <Foundation/Foundation.h>
#interface UIViewController (StatusBar)
-(void) addStatusBarBackground;
#end
Here is "UIViewController+StatusBar.m"
#import "UIViewController+StatusBar.h"
#implementation UIViewController (StatusBar)
-(void) addStatusBarBackground(){
//for making the background of the UIStatus bar black
UIView *statusBarView = [[UIView alloc] initWithFrame:CGRectMake(0, -20, [[self view] bounds].size.width, 22)];
statusBarView.backgroundColor = [UIColor blackColor];
[self.navigationController.navigationBar addSubview:statusBarView];
}
#end
And then I call the function in viewDidLoad of my controller after including UIViewController+StatusBar.h like so
[self addStatusBarBackground]; This is where the error happens, when this is called.
Thanks for the help in advance!
I figured out what I was doing wrong. It ended out to be nothing to do with the category. The category was implemented correctly except for the declaration -(void) addStatusBarBackground(). The parenthesis needed to be deleted. The problem was that I did not select the target memberships that my app has on the right panel in my UIViewController+StatusBar.m file. So the file was not being compiled for my project. I guess its kind of like it wasn't included. I haven't dealt with target memberships before so that was why I was unaware of the problem. Thanks for the comments helping me figure out the answer!

SIGABRT Error on my TabBarController when selecting the second tab

So I am making a card playing game where I have a UITabBarController and I have two tabs. Now the first tab is working perfectly fine but when I click on the other tab I receive this error
"Thread 1: signal SIGABRT" and on the debugger panel I have "argc = (int 1)" and argv = (char **) 0xbffff38c. I am using a story board for this project.
Below is my View Controller for the tab that throws me the error above.
If you need anymore code let me know but I was thinking it was probably a problem with my View since it won't even load.
#import "GameResultsViewController.h"
#import "GameResult.h"
#interface GameResultsViewController ()
#property (weak, nonatomic) IBOutlet UITextView *textResults;
#end
#implementation GameResultsViewController
- (void) updateUI
{
NSString* displayText = #"";
for (GameResult* gameResult in [GameResult allGameResults])
{
displayText = [displayText stringByAppendingFormat:#"Score: %d %# %0g\n",gameResult.score, gameResult.end, round(gameResult.duration)];
}
self.textResults.text = displayText;
}
- (void) setup
{
}
- (void) awakeFromNib
{
[self setup];
}
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
[self setup];
return self;
}
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self updateUI];
}
#end
this was also in the debugger window
2013-07-25 20:38:46.360 Matchismo[1119:c07] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<GameResultsViewController 0x758cce0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key display.'
*** First throw call stack:
(0x1c9b012 0x10d8e7e 0x1d23fb1 0xb84e41 0xb065f8 0xb060e7 0xb30b58 0x23a019 0x10ec663 0x1c9645a 0x238b1c 0xfd7e7 0xfddc8 0xfdff8 0xfe232 0x11f8c9 0x11f704 0x11dbda 0x11da5c 0x11f647 0x10ec705 0x202c0 0x20258 0x242ff4 0x10ec705 0x202c0 0x20258 0xe1021 0xe157f 0xe1056 0x246af9 0x10ec705 0x202c0 0x20258 0xe1021 0xe157f 0xe06e8 0x4fcef 0x4ff02 0x2dd4a 0x1f698 0x1bf6df9 0x1bf6ad0 0x1c10bf5 0x1c10962 0x1c41bb6 0x1c40f44 0x1c40e1b 0x1bf57e3 0x1bf5668 0x1cffc 0x297d 0x28a5)
libc++abi.dylib: terminate called throwing an exception
(lldb)
This part of your console log tells you what's going on:
[<GameResultsViewController 0x758cce0> setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key display.'
*** First throw call stack:
At some point in your app, an object is trying to set the 'display' property on an object of the GameResultsViewController class - but that class does not have this property.
It might be a stray outlet in Interface Builder if you've renamed a property - the old connection still exists in Interface Builder, so when the NIB loads the runtime tries to connect the outlet and fails with this error. Or you have a line of code somewhere where you have something like gameResultsViewController.display = ... and the display property is incorrect (either incorrectly named, or you haven't added to the GameResultsViewController class yet).
My 5c is on a renamed property being left in Interface Builder. Check out the outlet view on your ViewController to see if there's anything grayed out - usually indicates a broken property. Example here I renamed the button property to myButton - so you see the unconnected myButton property, and the warning on the button property.

'NSUnknownKeyException' with UIWebview

I'm trying to create an app that starts from a main page with three buttons on it. Each button pressed will switch to another view. Each view is just a blank view with a UIWebView on it. Transitioning to each page works fine when there's nothing on it. However, when I add the UIWebview and all the correct code, the transition to the page causes the app to crash with this error message:
* Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key viewWeb.'
* First throw call stack:
(0x1c94012 0x10d1e7e 0x1d1cfb1 0xb7de41 0xaff5f8 0xaff0e7 0xb29b58 0x233019 0x10e5663 0x1c8f45a 0x231b1c 0xf67e7 0xf6dc8 0xf6ff8 0xf7232 0x259b 0x10e5705 0x192c0 0x19258 0xda021 0xda57f 0xd96e8 0x48cef 0x48f02 0x26d4a 0x18698 0x1befdf9 0x1befad0 0x1c09bf5 0x1c09962 0x1c3abb6 0x1c39f44 0x1c39e1b 0x1bee7e3 0x1bee668 0x15ffc 0x1e92 0x1dc5)
libc++abi.dylib: terminate called throwing an exception
I'm positive all the UIWebView code is correct since I tested the exact same code in a new app that just runs on a single view and has no transitions. But here's the code I'm using for the transition:
- (IBAction)floorCatalog:(id)sender {
UIViewController* floorLampsViewController = [[UIViewController alloc] initWithNibName:#"floorLampsViewController" bundle:[NSBundle mainBundle]];
[self.view addSubview:floorLampsViewController.view];
}
- (void)dealloc {
[_floorLampsButton release];
[_tableLampsButton release];
[_wallLampsButton release];
[super dealloc];
}
- (void)viewDidUnload {
[self setFloorLampsButton:nil];
[self setTableLampsButton:nil];
[self setWallLampsButton:nil];
[super viewDidUnload];
}
And here's the code I'm using for the web views:
#property (retain, nonatomic) IBOutlet UIWebView *viewWeb;
[self.viewWeb loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.bing.com"]]];
Any reason why this keeps happening? Thanks!
Is viewWeb hooked up to the UIWebView in Interface Builder? It looks like viewWeb wasn't initialized or something, and seeing you're using an IBOutlet it makes me think it's in your nib.

NSInvalidArgumentException in Objective C

I'm making a simple calculator and when I use the addition button, the iOS Simulator crashes and I get an NSInvalidArgumentException. What do I do to prevent this from happening?
Error Report:
2013-06-23 17:18:54.574 Tutorial Test (Storyboard)[9744:c07] -[ViewController2 addition]:
unrecognized selector sent to instance 0x75858f0
2013-06-23 17:18:54.577 Tutorial Test (Storyboard)[9744:c07] *** Terminating app due to
uncaught exception 'NSInvalidArgumentException', reason: '-[ViewController2 addition]:
unrecognized selector sent to instance 0x75858f0'
*** First throw call stack:
(0x1c91012 0x10cee7e 0x1d1c4bd 0x1c80bbc 0x1c8094e 0x10e2705 0x162c0 0x16258 0xd7021
0xd757f 0xd66e8 0x45cef 0x45f02 0x23d4a 0x15698 0x1becdf9 0x1becad0 0x1c06bf5 0x1c06962
0x1c37bb6 0x1c36f44 0x1c36e1b 0x1beb7e3 0x1beb668 0x12ffc 0x1e2d 0x1d55)
libc++abi.dylib: terminate called throwing an exception
(lldb)
Code in ViewController that has this error:
View Controller.h
#import <UIKit/UIKit.h>
//Calculator
#interface ViewController2 : UIViewController{
IBOutlet UITextField *textField1;
IBOutlet UITextField *textField2;
IBOutlet UILabel *label;
}
-(IBAction)addition;
-(IBAction)subtract;
-(IBAction)multiply;
-(IBAction)divide;
-(IBAction)clear;
#end
View Controller.m
//Addition
-(IBAction)plus
{
float a = ([textField1.text floatValue]);
float b = a+([textField2.text floatValue]);
label.text = [[NSString alloc] initWithFormat:#"%2.f", b];
}
You named the method in the .m file plus, rather than addition. That is why the method addition isn't found, and the fix would be to rename the method in the .m file from plus to addition:
//Addition
-(IBAction)addition
{
float a = [textField1.text floatValue];
float b = [textField2.text floatValue];
label.text = [[NSString alloc] initWithFormat:#"%2.f", a+b];
}
Have you allocated an instance of the ViewController2 class?
For example:
ViewController2 *vc2 = [[ViewController2 alloc] init];
[vc2 addition];
Also, if the .m code you posted is the full contents of that file, then you're also missing
-(IBAction)addition {
...
}
You didn't inplement the right method.
You call addition but you never actually implement it. Declaring the method signature in the .h is not enough, you have to code the method.
This means that the selector that you are calling is not available on the class you called it against. The best thing to do is place a breakpoint where the method is being called. Go to the debugger and po your object.
po 0x75858f0
in this instance. However that number could be an object and it could be different. Look at the number in the console.
Make sure the object is of the proper class. Then check that class to make sure it responds to the selector you are calling.
Edit: Your problem is that your plus method should be renamed to addition. The names in the .h must match the names in the .m

iOS Accessing Property in parentViewController

My app is crashing when trying to access a method in my parentViewController. Here is the layout in StoryBoard
MainViewController = STLMMainViewController (ParentViewController)
Scene1 = STLMTimeDateViewController (ChildViewController)
Here is the code for STLMTimeDateViewController
#import "STLMTimeDateViewController.h"
#import "STLMMainViewController.h"
#interface STLMTimeDateViewController ()
#property (nonatomic, strong) STLMMainViewController *stlmMainViewController;
#end
- (void)viewDidLoad
{
[super viewDidLoad];
NSLog(#"The name of the controller %#",self.navigationController.parentViewController);
stlmMainViewController= (STLMMainViewController *) self.parentViewController;
[stlmMainViewController locationButtonSelected]; // This is where the App crashes
NSLog(#"TimeDateController");
}
The App Runs, but when STLMMainViewController is called, the app crashes with the following error:
2013-02-10 16:33:57.422 MyApp[9120:c07] The name of the controller <STLMMainViewController: 0x83850d0>
2013-02-10 16:33:57.434 MyApp[9120:c07] -[UINavigationController locationButtonSelected]: unrecognized selector sent to instance 0x8371a70
If I remove the following line:
stlmMainViewController = (STLMMainViewController *) self.parentViewController;
and just leave
[stlmMainViewController locationButtonSelected];
The App runs, no error, but the following method in [STLMMainViewController locationButtonSelected] does not get called (I never see the log):
-(void)locationButtonSelected
{
[LocationButton setSelected:YES];
[eatDrinkbutton setSelected:NO];
[timeCalButton setSelected:NO];
[carButton setSelected:NO];
[contactButton setSelected:NO];
NSLog(#"LocationButtonSelected Method");
}
All the properties in the locationButtonSelected method and the method itself is declared in .h of STLMMainViewController for public access.
Thanks
You might try this:
self.stlmMainViewController= (STLMMainViewController *)self.navigationController.parentViewController;
(EDIT: actually, as someone else just pointed out, you might want to use presentingViewController instead.)
It looks like you had it right in the log message right before this. You want your navigation controller's parent in this case.
BTW, the reason you don't crash when you delete this line, is because you end up sending the locationButtonSelected to nil. That won't crash, but it also won't do anything either.

Resources