addChildViewController giving NSException error? - ios

I am new to using this method so I could be doing this completely wrong so here is my code:
#property (nonatomic, weak) ConverterViewController *converterViewController;
#property (nonatomic, weak) CalculatorViewController *calculatorViewController;
If I am understanding this code correctly, these are acting as references to Two different ViewControllers.
Then I have this in my viewDidAppear method:
[self addChildViewController:_converterViewController];
[_converterViewController didMoveToParentViewController:self];
[self.view addSubview:_converterViewController.view];
I am getting an NSException at the first line when I try and add it as a child view controller. So not knowing whether or not this should then call some methods in my ConverterViewController class I put some breakpoints within that class both the initWithNibName and viewDidLoad methods and I found that neither of these methods are being called, so Im not exactly sure what is wrong. Then again Im not really sure what could go wrong so any help is greatly appreciated.
This is all I get from the console:
libc++abi.dylib: terminating with uncaught exception of type NSException

Updated Answer:
[self addChildViewController:_converterViewController]; does not create the converterViewController.
It simply takes the converterViewController object and adds it as a childViewController to self.
You will need to allocate memory and instantiate the object converterViewController before -addChildViewController: or else it's value will be nil and nothing will happen.
So... something this:
_converterViewController = [[ConverterViewController alloc] initWithNibName:#"ConverterViewController"
bundle:nil];
//now... adding it as childViewController should work
[self addChildViewController:_converterViewController];
[_converterViewController didMoveToParentViewController:self];
//optional: give it a frame explicitly so you may arrange more childViewControllers
//[_converterViewController.view setFrame:CGRectMake(0,0,100,100)];
[self.view addSubview:_converterViewController.view];

Related

ObjectiveC - [self.view viewWithTag] returning null

I am completely stumped and have been researching for days. Probably something really simple that I am missing.
I have a ViewController which contains a custom UIView called GameView, and a UIView called buttonBox which contains a "next level" button. What I am trying to achieve is when the level is completed in GameView, it fires a function in my ViewController which shows the buttonBox so the user can click the "next level" button. It simply will not work.
I have attempted this in 3 ways, neither have worked:
Creating an IBOutlet in the ViewController, connecting it to the hidden UIView (and it was definitely connected) and calling setHidden:NO.
Calling the [self.view viewWithTag:xxx] and then calling setHidden:NO.
Using hidden=NO instead of setHidden:NO.
Relevant code for ViewController as follows:
#interface PlayViewController : UIViewController
#property GameView *gv;
#property (strong, nonatomic) IBOutlet UIView *buttonBox;
-(void) showButtonBox;
#end
#implementation PlayViewController
#synthesize buttonBox;
...
- (IBAction)showButtonBox {
UIView *uiv = (UIView*) [self.view viewWithTag:999];
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"Showing box function");
NSLog(#"%#", uiv);
uiv.hidden = NO;
});
}
#end
And my custom view:
#implementation GameView
...
dispatch_async(bgQueue, ^{
_loopRunning = true;
//NSLog(#"Calling main loop...");
while ([self loopRunning])
{
...
PlayViewController * pvc = [[PlayViewController alloc]init];
[pvc showButtonBox];
...
}
#end
The thing is, the variable uiv is returning null in NSLog, which is obviously why hidden is not working, but I have no idea why. It also didn't work when I was using IBOutlet.
Also, current output from NSLog is as follows:
2015-11-24 00:18:38.612 ib[12579:1264539] Showing box function
2015-11-24 00:18:38.612 ib[12579:1264539] (null)
Thanks in advance.
Correct Answer:
The problem was that I was using StoryBuilder to build my UI, but by using the alloc init method was creating a new view controller (which is never shown) instead of correctly referencing the view controller which was being displayed. This is achieved by passing the view controller being displayed to the view in the viewDidLoad function, see below:
#implementation PlayViewController
#synthesize buttonBox;
#synthesize gv;
- (void)viewDidLoad
{
[super viewDidLoad];
gv = [self.view viewWithTag:777];
[gv setPlayViewController:self];
}
...
Man, it's simple. Let's take a look at:
#implementation GameView
...
dispatch_async(bgQueue, ^{
_loopRunning = true;
//NSLog(#"Calling main loop...");
while ([self loopRunning])
{
...
PlayViewController * pvc = [[PlayViewController alloc]init];
[pvc showButtonBox];
...
}
#end
Here we have the issue:
dispatch_async(bgQueue, ^{
I assume, bgQueue stands for "background queue", which means this is not served by the main thread (the UI thread).
Having that said, it's quite naive to expect
[pvc showButtonBox];
to work properly. Just move this code into the main thread. For instance, you can just wrap the aforementioned line of code into a dispatch_async on the main queue. That should solve your probem, if your outlets and/or tags are OK. Cheers.
[[PlayViewController alloc]init];
This creates a new instance of PlayViewController. Where have you defined your outlets and views?
In a storyboard? You can't use this initialiser - nothing from the storyboard will be picked up, you have to use a segue or initializeViewControllerWithIdentifier:.
In a xib file? Is it called PlayViewController.xib? If not, it won't be picked up by the initialiser. Plain alloc/init of a view controller will only find a nib file as described in the documentation of the nibName property.
Do you really want alloc / init at all? Do you actually want to make a new view controller, or is one already on the screen?
From your comments it seems option 3 is the right answer. The PlayViewController is already on the screen, alloc/init is creating a new instance of it, which is never being put on screen, which never loads any views regardless of storyboards or nibs.
You need to get a reference to the existing instance of PlayViewController. Without knowing the structure of your app it's not too easy to say how that's done - is it presenting the game view? Is the game view a subview of the view controller's view? You may need to pass in a reference (weak) to the game view when it is created, at viewDidLoad, or set up an outlet in the storyboard.

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!

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

UIScrollView loses reference to delegate

I need to create a number of UIScrollViews dynamically and fill them with content. This is all good except when i set the delegate to self and pan the list i get this exception:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFString scrollViewDidScroll:]: unrecognized selector sent to instance 0x7581230'
NSCFString obviously isn't my view controller (which implements the protocol UIScrollViewDelegate) so from what i gather somehow the memory gets messed up and it doesn't keep the reference correctly. Occasionally this can be something else too which strongly points to something being wrong with the memory
Here's the code to create the list:
for (NSUInteger i = 0; i < self.stories.currentStory.selectableWordCount; i++) {
UIScrollView *list = [[UIScrollView alloc] init];
list.alwaysBounceVertical = YES;
list.showsVerticalScrollIndicator = NO;
list.clipsToBounds = NO;
list.delegate = self;
list.pagingEnabled = YES;
[self.view addSubview:list];
.. // add UILabels to the list, set the frame, contentSize etc
[self.wordLists addObject:list]; // this is a #property (nonatomic, strong) NSMutableArray, declared in a private interface()
}
If i NSLog the delegate it's correct. respondsToSelector also matches fine. Interestingly if i comment out the scrollViewDidScroll: respondsToSelector: doesn't match any more and (probably because of this) the UIScrollView won't attempt to call this method any more. This then means that it can reach the delegate correctly to check for the method availability but when it gets called something goes wrong.
I'm targeting iOS5 with ARC. If this wasn't the case i would assume that i messed something up with the memory myself but now i don't have the same control.
I'm having a hard time debugging this issue, any help on how to proceed would be appreciated
D'uh. I was obviously looking in the wrong place. The view controller was added through a .xib and the view was pointing to a subview on the stage. However i needed to create an IBOutlet to the view controller in the main view controller to make sure it stays in memory. Hopefully this can help somebody else with a similar problem :)

Crasher in a custom view as UINavigationControllers navigationItem.titleView

I have an UIViewController with several subviews in its view property (UISearchbar and several UIButtons). The UIButtons hooked up to typical IBActions like -(IBAction)buttonPressed:(id)sender for the UIControlEventTouchUpInside state - it doesn't matter if I do it in IB or programmatically.
- (void)viewDidLoad {
MUZTitleViewController *title = [[MUZTitleViewController alloc]
initWithNibName:nil bundle:nil];
self.navigationItem.titleView = title.view;
}
In my project there's also an UINavigationController. When I set the navigationItem.titleView of the UINavigationBar to the view of my UIViewControllers view I get an EXC_BAD_ACCESS exception, as soon as I tap one of the button. I don't know why this is.
I uploaded a small sample project to illustrate my problem: Test010.xcodeproj (it's ARC enabled)
More and more I come to the conclusion that it's not a good idea to use the UIViewControllers view and assign it to the titleView but I don't see any alternative here.
Edit: Sorry, the sample project commented out the call which causes the exception. I reuploaded the linked project file.
Edit^2: As PengOne pointed out I've skipped the exact error message I got:
2011-09-10 23:09:50.621 Test010[78639:f803] -[CALayer buttonPressed:]: unrecognized selector sent to instance 0x9254ae0
2011-09-10 23:09:50.623 Test010[78639:f803] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[CALayer buttonPressed:]: unrecognized selector sent to instance 0x9254ae0'
Have you tried setting NSZombieEnabled to YES? If I do this, the console shows the following output:
2011-09-10 22:56:23.329 Test010[6481:ef03] *** -[MUZTitleViewController
performSelector:withObject:withObject:]: message sent to deallocated
instance 0x7a7ff70
As the project is ARC enabled, the controller seems to get deallocated some time after this line:
MUZTitleViewController *title = [[MUZTitleViewController alloc] initWithNibName:nil bundle:nil];
I am not sure what the best solution is, but a property definitely helps to prevent the exception like so:
// MUZDetailViewController.h
#property (strong, nonatomic) MUZTitleViewController *title;
// MUZDetailViewController.m
#synthesize title;
self.title = [[MUZTitleViewController alloc] initWithNibName:nil bundle:nil];
self.navigationItem.titleView = title.view;
The problem that you were having with ARC can also be resolved by setting the initial view controller of your application as your main window's rootViewController property instead of using addSubview.
Doing this avoids the need to add each custom view controller as a property.

Resources