After a lot of search, and tries with some solutions on stackoverflow, i didn't find any answer which could solve my error :
I have a UIViewcontroller, who's name is WorldViewController. In this UIViewcontroller, i had init some UIViews. I want to modificate some variables which depends of WorldViewController from some UIViews. And now that i put those lines :
WorldViewController * World = [[WorldViewController alloc] init];
it gives me :
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'
So, how to fix it ? Could it comes from the fact that WorldViewController is running ? And so, how to fix it ?
Edit : init method of my viewcontroller
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
World1 = [[UIView alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 480.0)];
[World1 setBackgroundColor:[UIColor blackColor]];
[self.view addSubview:World1];
[World1 release];
[self.view addSubview:ViewPig];
[self.view addSubview:level1view];
[self.view addSubview:level2view];
[self.view addSubview:LoadView];
[LoadView AnimPigLoadingWith:PigChargement];
[LoadView AppearLabelLoading];
[self.view addSubview:FondPauseGrise];
[self.view addSubview:FondPause];
[self.view addSubview:BoutonResume];
[self.view addSubview:BoutonHome];
[self performSelector:#selector(Chargement) withObject:nil afterDelay:0.5];
[self performSelector:#selector(ViewAppears) withObject:nil afterDelay:5.5+2.5];
[self performSelector:#selector(LabelPrevientDepartWithImage:) withObject:Trois afterDelay:9];
[self performSelector:#selector(LabelPrevientDepartWithImage:) withObject:Deux afterDelay:10];
[self performSelector:#selector(LabelPrevientDepartWithImage:) withObject:Un afterDelay:11];
[self performSelector:#selector(LabelPrevientDepartWithImage:) withObject:Go afterDelay:12];
[self performSelector:#selector(Lancement) withObject:nil afterDelay:(3)];
[self performSelector:#selector(GestionMaps) withObject:nil afterDelay:(11+2)];
}
return self;
}
Thanks !
I had a similar problem. My mistake was in not marking the view that I was trying to load as the initial view controller. My guess is that the there was no initial view controller to add to the array and hence the object was nil. I'm not sure how good this is at answering your question but it worked for me.
You haven't listed enough code in your question to definitely show where you're making an error.
Look in your code for any lines that say "insertObject:atIndex:". The object you're inserting is apparently nil.
If you can't find this line, add a symbolic breakpoint on the symbol "[NSArray insertObject:atIndex:]" (click the link to see specific instructions in an answer of a closely related question to yours) and see if you can break on it right before the crash happens.
Related
I am trying to subclass UIView as BottomNavBar (code below).
I get the following error
'-[UIView setCenterImage:]: unrecognized selector sent to instance 0x14dc5050'
setting a couple of breakpoints the error comes from this line
self.centerImage=[UIImage imageNamed:#"icon_OK.png"]; //I used it just for testing it should be as follows:
self.centerImage=centerIcon;
BottomNavBar.m
- (id)initWithFrame:(CGRect)frame centerIcon:(UIImage*)centerIcon withFrame:(CGRect)centerFrame
{
self = [super initWithFrame:frame];
if (self) {
self=[[UIView alloc]initWithFrame:frame];
[self setBackgroundColor:UA_NAV_BAR_COLOR];
//--------------------------------------------------
self.centerImage=[UIImage imageNamed:#"icon_OK.png"]; //for testing
//self.centerImage=centerIcon; >>this is the one that should be used
self.centerImageView=[[UIImageView alloc]initWithFrame:centerFrame];
self.centerImageView.image=self.centerImage;
[self addSubview:self.centerImageView];
}
return self;
}
cropPhoto.m (where I'm trying to show an object of that class...)
CGRect bottomBarFrame = CGRectMake(0, self.view.frame.size.height-UA_BOTTOM_BAR_HEIGHT, self.view.frame.size.width, UA_BOTTOM_BAR_HEIGHT);
NSLog(#"UA_icon_ok: %#", UA_ICON_OK);
self.bottomNavBar = [[BottomNavBar alloc] initWithFrame:bottomBarFrame centerIcon:UA_ICON_OK withFrame:CGRectMake(0, 0, 90, 45)];
[self.view addSubview:self.bottomNavBar];
can anybody help on what's going wrong here?
self=[[UIView alloc]initWithFrame:frame];
Remove this line. Your view is already initialised, now you're replacing the value of self with a plain UIView.
I'm surprised you're not seeing a compiler warning here.
I create a CustomView:UIView with XIB, load and addObserver for a NSInteger property like that:
//CustomView.h
#interface CustomView : UIView
#property (nonatomic) NSInteger inputStateControl;
#end
//CustomView.m
static void *kInputStateControlObservingContext = &kInputStateControlObservingContext;
#implementation CustomView
- (id)init
{
self = [super init];
if (self) {
// Initialization code
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomView" owner:self options:nil];
self = [nib objectAtIndex:0];
//
[self commonInit];
}
return self;
}
-(void)commonInit{
[self addObserver:self forKeyPath:#"inputStateControl" options:NSKeyValueObservingOptionOld context:kInputStateControlObservingContext];
}
#pragma mark Observer
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if ( context == kInputStateControlObservingContext ) {
NSInteger oldState = [[change objectForKey:NSKeyValueChangeOldKey] integerValue];
if ( oldState != self.inputStateControl ) {
NSLog(#"CONTEXT change %i to %i",oldState,self.inputStateControl);
}
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
-(void)dealloc{
[self removeObserver:self forKeyPath:#"inputStateControl"];
// [self removeObserver:self forKeyPath:#"inputStateControl" context:kInputStateControlObservingContext];
}
#end
Everything work OK if I comment out removeObserver in dealloc, here is the log:
CONTEXT change 0 to 2
But when removeObserver, App crash:
*** Terminating app due to uncaught exception 'NSRangeException', reason: 'Cannot remove an observer <Keyboard 0x6a8bcc0> for the key path "inputStateControl" from <Keyboard 0x6a8bcc0> because it is not registered as an observer.'
No crash when comment load CustomView.xib but nothing to do without XIB.
What's wrong in my code?
How to add and removeObserver for an NSInteger property inside CustomView with Custom Xib?
Thanks in advance!
*EDIT: I add my code to make my question clear. Please help!
https://github.com/lequysang/github_zip/blob/master/CustomViewKVO.zip
Here's what's happening - in your viewDidLoad method, you call [[CustomView alloc] init]. This creates a new CustomView instance, and calls init on it. However, in init, you load a new instance from the nib and replace self with the one from the nib. This causes the instance that you created from alloc and set up with the self = [super init]; to be deallocated as there are no more strong references to it. Since this instance is deallocated before calling commonInit, it never observes its own properties so removing itself as an observer causes the exception.
One way to fix this would be to just load the view directly from the nib in your view controller, or create a class method on CustomView
NSArray *topLevelObjects = [[NSBundle mainBundle] loadNibNamed:#"CustomView" owner:nil options:nil];
CustomView *customView = topLevelObjects[0];
If you do take that approach, discard you init implementation and replace it with an initWithCoder: that does this:
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
_inputStateControl = 0;
[self commonInit];
}
return self;
}
The reason for implementing initWithCoder: is that it will be called automatically when you load the view from the nib. You just have to implement it and you will be able to do the setup that you are already doing in init. Also make sure your dealloc is implemented like so:
-(void)dealloc{
[self removeObserver:self forKeyPath:#"inputStateControl" context:kInputStateControlObservingContext];
}
I don't know exactly why what you're doing isn't working, but having an object observe itself like this strikes me as a bad idea. You should just implement your inputStateControl's setter explicitly (setInputStateControl) and do your logging and whatever other side effects you want in that setter method.
While not an ideal solution by any means, surrounding the remove with a try-catch block will resolve your issue. If in fact the observer is not registered, ignoring an exception during removing it is safe. The main risk is whatever assumption your app is relying on that it IS registered.
Not sure why you're facing the problem.The most short cut way i do is by setting the custom observer to 'nil' in the dealloc ;) ,but in your case to use that shortcut way also you need to add the obeserver in some other way around.
Ok at least i can tell you is,in your dealloc,
-(void)dealloc{
[[NSNotificationCenter default center] removeObserver: self];
[self removeObserver:self forKeyPath:#"inputStateControl"];
//OR
//If you had create a observer called "temp",then easy way to remove the observer is temp=nil;
}
If you're still hanging in,put the #try #catch blocks for the temporary solution,note that its not going to remove the observer ;)...
Not the perfect the answer you were looking for,but its just the way i think...Happy coding :-)
I created three files: MyViewController.h, 'MyViewController.m, MyViewController.xib. In thexib` file I created one UIScrollView as the root level element and made all necessary connections to its file owner.
In my .m file, I overwrite the loadView method to set some additional properties of the ScrollView.
-(void)loadView{
[super loadView];
UIScrollView *tmp = (UIScrollView *)[self view];
[tmp setMaximumZoomScale:3.0]; // crashed here
}
However, the code crashed at the last line of the function, the log said:
-[UIView setMaximumZoomScale:]: unrecognized selector sent to instance 0x1cda5d60
It seems that tmp was recognized as a UIView, not a UIScrollView despite the explicit cast. It's my understanding that [super loadView]; will load the view from the xib file and set the view of the ViewController. It didn't help even when I moved the crashed line of code to the viewDidLoad function.
Edit:
I found similar pattern in Apple's documentation site:
- (void)viewDidLoad {
[super viewDidLoad];
UIScrollView *tempScrollView=(UIScrollView *)self.view;
tempScrollView.contentSize=CGSizeMake(1280,960);
}
Edit 2:
I somewhat narrowed the problem. Now I've moved the code that casts [self view] to viewDidLoad, and the error occurs only when I override loadView. If I add
-(void)loadView{
[super loadView];
}
The error will occur. If I delete these three lines, no error. But isn't the call to super totally the same as not overriding at all? Why the difference?
Check whether the connections inspector for the connections to files owner is like this or not for scroll view...
See the below picture...
Then place your code like this in viewDidLoad...
- (void)viewDidLoad
{
[super viewDidLoad];
UIScrollView *tempScrollView=(UIScrollView *)self.view;
[tempScrollView setMaximumZoomScale:3.0];
}
This is working fine for me.
Edit 2:
-(void)loadView{
[super loadView];
UIScrollView *tempScrollView=(UIScrollView *)self.view;
tempScrollView.contentSize=CGSizeMake(320,960);
[tempScrollView setBackgroundColor:[UIColor grayColor]];
[tempScrollView setMaximumZoomScale:3.0];
}
This is also working fine for me.
I have a UIViewController with a custom init method that looks like this:
- (id)initWithFrame:(CGRect)frame_ customObject:(CustomObject *)object_ {
if(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self = [super initWithNibName:#"ArtistViewController_iPad" bundle:nil];
} else {
self = [super initWithNibName:#"ArtistViewController" bundle:nil];
}
[self.view setFrame:frame_];
self.customObject = object_;
return self;
}
But when [self.view setFrame:frame_]; is called, it crashes with this in the log:
(null)
libc++abi.dylib: terminate called throwing an exception
This is how I allocate the UIViewController from another UIViewController:
CGRect frame = self.view.frame;
artistViewController = [[ArtistViewController alloc] initWithFrame:frame customObject:anObject];
the frame exists. self exists from [super initWithNibName:bundle];
But self.view seems to not exist. The nib files exist and have their view outlet hooked up.
Why does this happen?
You should not access the view from within the initializer. There are several more appropriate places to do this work, depending on what you really want to accomplish.
Read the view controller lifecycle to understand where you may want to place your modifications.
http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10-SW1
I have a view controller that initializes two other view controllers. The view for one controller wasn't showing, and I tracked the problem to the instance being nil when it's added to the superview.
Here is the code. viewDidLoad is being called before the favoritesTableVC is initialized. I can see this by placing breakpoints in the initialization methods of the resultsTableVC and favoritesTableVC view controllers.
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
resultsTableVC = [[[ResultsTableVC alloc] initWithController:self andTableView:nil] retain];
favoritesTableVC = [[[FavoritesTableVC alloc] initWithFrame:CGRectMake(0, 10, self.view.frame.size.width, defaultFavoritesTableHeight) andController:self] retain];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:resultsTableVC.view];
[resultsTableVC release];
[self.view addSubview:favoritesTableVC.view];
[favoritesTableVC release];
}
Here is the order the methods are being called:
allResults init
resultsTableVC init
allResults viewDidLoad
addSubview allResultsVC
addSubview favoritesResultsVC
favoritesResultsVC init
This is a single thread, so I don't understand how viewDidLoad can be called before init is complete.
-[ResultsTableVC initWithController:andTableView:] is probably referencing allResults.view.
This would force the allResults controller to load its view (which then of course causes viewDidLoad to fire). All of this happens synchronously, before you actually return from initWithController:andTableView:
I'm taking a guess, but could you try this :
favoritesTableVC = [[[FavoritesTableVC alloc] initWithFrame:CGRectMake(0, 10, SOME_HARD_CODED_INT, SOME_HARD_CODED_INT) andController:self] retain];
And see if you get the same result.
My guess is that self.view is pointing to nil at that time.
But that wouldn't explain why the init is call after... but no harm in trying.
(I haven't tested it)