Removing View from its superview getting a bad access error XCODE - objective-c

since the release of the storyboard it has been a long time since I've used addSubview and removeFromSuperview. Obviously I have forgotten how to use them.
So on my UIViewControllerA I have this code for a button:
- (IBAction)buttonClickHandler:(id)sender {
dyf_FacebookViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"Facebook"];
[self.view addSubview:controller.view];
}
Which loads a UIView that is handled by UIViewControllerB. now this view can be called by many different ViewControllers to be a subview, which is why I have it remove itself from the superview.
So on UIViewControllerB I have this code:
- (IBAction)close:(id)sender {
[self.view removeFromSuperview];
}
Unfortunately that returns with a bad access error. Please help!
Thanks
Michael
EDIT:
The subview added (subview's viewcontroller) will be in control for removing itself as it is in control of the button on the subview. So I do not have access to the original controller.view variable as that is in ViewControllerA

You'll have to keep a reference to your dyf_FacebookViewController object, so you can do the following:
- (IBAction)close:(id)sender {
[controller.view removeFromSuperview];
}
What you're doing now is to remove your main view from its superview, which can have serious consequences, giving you a bad access.

if ([controller.view superView]) {
[controller.view removeFromSuperview];
}

Try this
- (IBAction)close:(id)sender {
for (UIView *subView in self.view.subviews) {
[subView removeFromSuperview];
}
}

If you want to remove the view you added, then keep a copy of the view controller...
// in this VC.m
#interface
#property (nonatomic, strong) dyf_FacebookViewController *dyfController;
#end
- (IBAction)buttonClickHandler:(id)sender {
self.dyfController = [self.storyboard instantiateViewControllerWithIdentifier:#"Facebook"];
[self.view addSubview:self.dyfController.view];
}
Later, to close the view...
[self.dyfController.view removeFromSuperview];

Related

Auto layout on subview inside subview (NSView)

I'm having hard time trying to properly set the auto layout for a subview inside another subview.
I'm using an example where two toolbar items show two different subviews (which works as expected), and those two share a third subview that's the one that does not fit well.
The code to add the subview is very simple:
[subView removeFromSuperview];
[itemXSubView addSubview:subView];
[self.window setContentView:itemXView];
First I remove the third and shared subview (subView) in case it was already added, then add it to the item[1-2]SubView and set the content of the window with the subview item[1-2]View, [1-2] depending on the toolbar button selected. Everything else is done with auto layout conditions.
The result is that the third and shared subview is always misplaced and/or cut, as in the example below. Resizing the window and changing from the first or the second view usually aggravates the issue.
Example of third subview items cut
Test updates
Tried to delegate the main window and override two resize functions (as per #the4kman suggestions), but they did never get called. The init is the only being called:
#interface viewController: NSView <NSWindowDelegate>
#end
#implementation viewController
-(id)init
{
if((self=[super init])) { }
return self;
}
- (void)resizeSubviewsWithOldSize:(NSSize)oldSize;
{
[super resizeSubviewsWithOldSize:oldSize];
}
- (void)resizeWithOldSuperviewSize:(NSSize)oldSize;
{
[super resizeWithOldSuperviewSize:oldSize];
}
- (void)layout
{
[super layout];
}
Another suggestion that got called, but sadly with no actual improvement. Delegated the window to viewController and set the main view (self.view) to the nested subView. Tried also combining with [itemXSubView setNeedsLayout:true];:
#interface viewController: NSViewController <NSWindowDelegate>
#end
#implementation viewController
-(void)viewWillLayout
{
[super viewDidLayout];
[self.view setNeedsLayout:true];
}
#end
Thanks in advance!
itemXSubView resizes its subviews but it doesn't fit them. You have to fit subView inside item1SubView before addSubview.
- (IBAction)item1Action:(id)sender {
NSLog(#"Item 1 action triggered");
[subView removeFromSuperview];
subView.frame = item1SubView.bounds;
[item1SubView addSubview:subView];
[self.window setContentView:item1View];
}

How can I hide/remove a subview by default when it's superview loaded but still have access to it?

I have a view which displays a UILabel and UITextField subviews as well as an UIImageView and 2 UIButtons. These all make up a form. One of the fields is dedicated to date entry in dd/mm//yyyy format.
I decided to create another view (called datePickerView) inside my main view which holds a UIDatePicker instance. When the date field on the form mentioned above is clicked this view with the datepicker is show. Upon clicking the done button the view is hidden/removed again.
I have methods that deal with the showing and hiding of this view:
#property (weak, nonatomic) IBOutlet UIView *datePickerView;
- (void) hidePickerView {
[UIView animateWithDuration:0.5
animations:^{
[[self datePickerView] setFrame:CGRectMake(0, -250, 320, 50)];
} completion:^(BOOL finished) {
[[self datePickerView] removeFromSuperview];
}];
}
- (void) showPickerView {
[[self view] addSubview:[self datePickerView]];
[[self datePickerView] setFrame: CGRectMake(0, -250, 320, 50)];
[UIView animateWithDuration:1.0
animations:^{
[[self datePickerView] setFrame: CGRectMake(0, 152, 320, 260)];
}];
}
I call these methods in my textFieldDidEndEditing and textFieldShouldBeginEditing UITextField delegate methods.
My problem is the the view with the datepicker is visible when it's superview is first loaded. I tried dragging this datepicker view to the top of the hierarchy above all the textfields and buttons but this only shifts the view behind them.
I've also tried hiding the view through storyboard interface, tried adding a hide method to viewDidLoad, viewWillAppear. The methods I tested were:
[self datePickerView] removeFromSuperview];
[[self datePickerView] setHidden:YES];
[self hidePickerView];
These hide the datePickerView no problem but when I click the textfield the datePickerView doesn't show.
- (BOOL)textFieldShouldBeginEditing:(UITextField *)textField {
// missing since date field error checking
if (textField == [self missingSinceField]) {
[self showPickerView];
return NO;
}
return YES;
}
-(void)textFieldDidEndEditing:(UITextField *)textField {
if (textField == [self missingSinceField]) {
[self hidePickerView];
}
}
When I don't hide or remove the datePickerView in any way shape or form and tap it the datePickerView is loaded no problem.
** Just before posting this question I set a breakpoint in my showDatePicker method and when I uncomment [self datePickerView] removeFromSuperview]; I see that my datePickerView outlet is nil so this may explain why I'm having the issue I'm having. Commenting it again and trying again shows it as not being nil.
I think this is what's wrong but not sure how to make sure when viewDidLoad is run that my datePickerView isn't nil. I can't have it showing in the background of the form under the text fields and I don't think changing the colour of it to white so users can't see it isn't elegant.
Help would be appreciated.
Kind regards
I guess your IBOutlet property for datePickerView is weak, so, when you remove it from the superview it gets destroyed.
Either make it strong, or use the hidden property instead (remembering to set hidden to NO in showPickerView and YES in hidePickerView - where you currently add and remove the view).
You probably want to use the hidden property of the UIView subclass you are working with.
Source:
UIView reference
As far as your outlet being nil - make sure you have connected the IBOutlet to an actual element in the storyboard.

removeFromSuperview doesn't work properly

In class
#interface StartScene : UIView
I call an instance of
#interface HelpView : UIView {
GameOverMenu* gorm;
PlayScene* tView;
}
and use addSubview. I also got huge code here
-(void) removemyself {
[tView removeFromSuperview];
[gorm removeFromSuperview];
[self removeFromSuperview];
}
-(void)restartPlay {
[tView removeFromSuperview];
[self playSceneDidLoad];
}
-(void)gameOverDidLoad {
[tView removeFromSuperview];
gorm = [[GameOverMenu alloc]initWithFrame:CGRectMake(0, 0, 320, 520)];
gorm.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"backGround.jpg"]];
[gorm checkScore:Scores];
[self addSubview:gorm];
}
-(void)playSceneDidLoad {
[gorm removeFromSuperview];
tView = [[PlayScene alloc]initWithFrame:CGRectMake(0, 0, 320, 520)];
tView.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"backGround.jpg"]];
[self addSubview:tView];
[tView ooneFingerTwoTaps];
}
And two sub classes of HelpView:
#interface PlayScene : HelpView
#interface GameOverMenu : HelpView <UITextFieldDelegate>
In StartScene when I push on a button, an instance of HelpView is created and in init method playSceneDidLoad is called.
Inside the PlayScene there is restart button which calls restartPlay method. When game is lost gameOverDidLoad method is called.
And In both PlayScene and GameOverMenu there are quit button, which calls removemyself method, that are supposed to return player to the main menu.
At first glance it should work fine, but if I press restart button for several times and than try to press Quit, it occurs that the views were not removed from superview, one press on a quit button only now removes them one by one.
And we stop on the HelpView, it didn't remove itself (even if I try to call [super removeFromSuperview]; somewhere.
I need to remove views correctly in time and to get to the main menu (StartScene) when quit is pressed. I don't think that a lot of views covering each other is a good variant. What is the problem?
Well I occurs that the point is that if super class' method is called from the subclass and there is such a command [self removeFromSuperview]; or [(someOtherSubview) removeFromSuperview];, it is subclass that uses self or (someOtherSubview). If our subclass doesn't have the pointed subView, than the command would do nothing. And if there is [self removeFromSubview];, subclass would remove itself.
Actually I solved this problem by using buttons as subView of superclass.

Problems with storyboard

recently I started using storyboard and I've the following situation: I want to set the text of an UILabel from the AppDelegate. So I created an instance of my ViewController
UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
ViewController *controller = (ViewController*)[mainStoryboard
instantiateViewControllerWithIdentifier: #"mainViewController"];
myViewController = controller;
[window addSubview:myViewController.view];
[window makeKeyAndVisible];
and called the following method from the delegate
- (void) updateParameterLabel:(NSString *)parameter {
NSLog(#"URL-2: %#", parameter);
parameterLabel.text = parameter;
}
But the parameter is not shown in the UI.
Another think, which is kind of strage:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
NSLog(#"View did Appear");
}
The "View did appear" is logged twice ...
Any hints?
Regards,
Sascha
Setting the text of a UILabel from your application delegate isn't great design. Your view controllers should be managing the content of your views, hence their name. Typically your storyboard is instantiated automatically, and you don't need any of the storyboardWithName et code you've got, assuming you're working with Apple's default templates.
Maybe think about re-architecting your application to follow the 'model-view-controller' pattern more strictly, and also look at how Apple instantiate storyboards automatically (just create a new storyboard project in XCode to see this).
If you still want to make it work, make the UILabel a property of your viewcontroller and set the label by using
In delegate :
- (void) updateParameterLabel:(NSString *)parameter {
NSLog(#"URL-2: %#", parameter);
[myViewController updateParemeter:parameter];
}
In myViewController:
- (void) updateParameterLabel:(NSString *)parameter {
NSLog(#"URL-2: %#", parameter);
parameterLabel.text = parameter;
[self.view setNeedsDisplay];//edit
}
So use the viewController to update your label. Of course you need the label as a property in your viewController
For what I see you are trying to update the label before it appears, so why don't you try calling your updateLabel method in the viewWillAppear, it would be something like this
-(void)viewWillAppear:(BOOL)animated{
[self updateParameterLabel:#"Some Text"];
[super viewWillAppear:YES];
}
And updateParameterLabel has to be implemented in the viewController.

Add a UITableViewControler to a UIView

I am writing an appcelerator module, which means I am handed a subclassed UIView to work with and create my visual controls in Objective C.
I am trying to add a tableview with a searchbar, but most samples online use rootViewController and UITableViewControler.
so...in order to add a tableview to the current view, do I need to create a tableview and a UITableViewController and add them somehow as subviews to the current view ?
I tried adding a MainViewController.h & MainViewController.m which is defined as
#interface MainViewController : UITableViewController <UISearchDisplayDelegate, UISearchBarDelegate>
and then in my view
#import "MainViewController.h"
- (void)viewDidLoad
{
mainView = [[MainViewController alloc] init];
[self addSubview:mainView.view];
}
-(void)frameSizeChanged:(CGRect)frame bounds:(CGRect)bounds
{
if(CGRectIsEmpty(self.frame))
{
self.frame = bounds;
[self addSubview:mainView.view];
}
}
but it did not work, I just got an empty view. any ideas ? a sample code would be greatly appreciated
thanks
You could try something like this:
- (void)viewDidLoad {
self.view.backgroundColor=[UIColor whiteColor];
UITableView *TableListView=[[UITableView alloc] initWithFrame:CGRectMake(-5,-1,331,425) style:1];
TableListView.editing=NO;
TableListView.delegate=self;
TableListView.dataSource=self;
TableListView.separatorColor=[UIColor colorWithRed:0.000000 green:0.591928 blue:1.000000 alpha:1.000000];
TableListView.separatorStyle=1;
TableListView.rowHeight=40;
TableListView.tag=0;
TableListView.backgroundColor=[UIColor groupTableViewBackgroundColor];
TableListView.clipsToBounds=YES;
[self.view addSubview:TableListView];
[TableListView release];
}
Hope this helps get you started...