How to get rid of EXC_BAD_ACCESS - objective-c

So, another EXC_BAD_ACCESS topic on StackOverflow, but as I'm new to Objective-C this is still a topic I don't really grasp yet. Even though I have done a lot of research about it already.
The issue is the following. I have a UIScrollView that I have overwritten using a Custom Class (named MultiSelectView). If the user taps this UIScrollView and then I want to open a view that allows him to select some data.
So I have declared a UITapGestureRecognizer that calls the openMultiSelect: method. But on the line [parent.navigationController pushViewController:view animated:YES]; I get a Program received signal: "EXC_BAD_ACCESS". error. Why o why?
- (id) initWithCoder:(NSCoder *) coder {
self = [super initWithCoder: coder];
if (self) {
// Add a Tap Gesture Recognizer to the Scrollview.
// If the user taps the view, it triggers the 'openMultiSelect' method.
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(openMultiSelect:)];
[singleTap setNumberOfTapsRequired:1];
[singleTap setNumberOfTouchesRequired:1];
[self addGestureRecognizer:singleTap];
}
return self;
}
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
[view release];
}
So the parent that you see is a ViewController that contains the tab. Is there a better way to do this? Because for now I have thus a ViewController that contains Tabs. In its activateTab: method I thus create the tab and pass self along. I do the same in the viewDidLoad for that tab to pass the parent to the custom UIScrollView:
- (void) activateTab:(int)index {
... code ...
self.tab_Basic = [[TabBasic alloc] initWithNibName:#"TabBasic" bundle: [NSBundle mainBundle]];
self.tab_Basic.parent = self;
... code ...
}

You should make some change to your callback method. Something like that:
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
if(gesture.state == UIGestureRecognizerStateEnded){
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];
[view release];
}
}

What you are doing wrong is releasing the object "view" too early, don't release it until the view is popped. That should fix the problem.
- (void)openMultiSelect:(UIGestureRecognizer *)gesture {
//int myViewTag = gesture.view.tag; // now you know which view called
DataSelectView *view = [[DataSelectView alloc] initWithNibName:#"DataSelectView" bundle:[NSBundle mainBundle]];
view.allowMultiSelect = YES;
[parent.navigationController pushViewController:view animated:YES];

Related

Creating multiple subviews inside view controller

I have a view controller named ViewController.
ViewController displays a UIView that has a button on it, which allows me to advance to a second view controller - SecondViewController.
SecondViewController also has a button on it, which allows me to advance to a third view controller.
However, I am having trouble displaying ThirdViewController. When I tap the button in SecondViewController it throws an error:
Warning: Attempt to present ... on ... whose view is not in the window hierarchy!
I have been to a bunch of other sites and posts that address this issue, but cannot seem to find a working solution. I have implemented quite a few solutions, but none seem to work.
Here is my code:
- (void)secondaryView:(UIView *)secondaryView
{
UIView *theView = secondaryView;
UIViewController *viewController = [[UIViewController alloc] init];
viewController.view.frame = [UIScreen mainScreen].bounds;
[viewController.view addSubview:theView];
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:viewController animated:YES completion:nil];
}
secondaryView is a UIView that I am constructing elsewhere in the application. I add it to the viewController then present the viewController.
Is there any way to dynamically create UIViewControllers, add a UIView to each one, and add them to the window hierarchy?
If you can use navigation in your ViewControllers, you can try the below code
In the place where you call the firstViewController,
-(void)callFirst
{
FirstViewController *first = [FirstViewController alloc] init];
UINavigationController *navigationController = [UINavigationController alloc] initWithRootViewController:first];
navigationController.modalPresentaionStyle = UIModalPresenationFormSheet;
[self presentModalViewController:navigationController animated:YES];
}
And in the FirstViewController button action ,you can write
-(void)callSec
{
SecondViewController *sec = [SecondViewController alloc] init];
[self.NavigationController pushViewController:sec animated:YES];
}
And in SecondViewController you can do the same
-(void)callThird
{
ThirdViewController *third = [ThirdViewController alloc] init];
[self.NavigationController pushViewController:third animated:YES];
}
Try this...And in these ViewControllers you can do whatever coding you want to meet the requirement like
-(void)viewDidLoad
{
UIView *newView = [[UIView alloc] initWithFrame:CGRectMake(20,20,400,400)];
newView.backGroundColor = [UIColor redColor];
[self.view addSubView:newView];
}

MGSplitViewController as Modal not working correctly

I am trying to use an MGSplitViewController, but rather than having it set as the rootViewController, I want it to show modally. This is the code I am using so far
- (void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath: (NSIndexPath *)indexPath
{
if(splitViewController == nil)
{
self.splitViewController = [[MGSplitViewController alloc] init];
self.rootViewController = [[RootViewController alloc] init];
self.detailViewController = [[DetailViewController alloc] init];
}
[splitViewController setViewControllers:[NSArray arrayWithObjects:rootViewController, detailViewController, nil]];
if (NO) { // whether to allow dragging the divider to move the split.
splitViewController.splitWidth = 15.0; // make it wide enough to actually drag!
splitViewController.allowsDraggingDivider = YES;
}
splitViewController.delegate = detailViewController;
[rootViewController performSelector:#selector(selectFirstRow) withObject:nil afterDelay:0];
[detailViewController performSelector:#selector(configureView) withObject:nil afterDelay:0];
[self presentViewController:splitViewController animated:YES completion:nil];
}
This works almost fine, but the buttons in the detailViewController do not work. They do nothing. Also, when I click a button in the left panel, the text doesn't change in the detailViewController as it does in the same project.
Am I missing something?
I'm also working with MGSplitViewController, but it sounds to me like you need to set up some communication between your master and detail views. If you look at the demo project, you can see they use delegates to that effect.

Instance variables not working in ViewController in UINavigationController

I'm still new to iOS development but I've ran into a problem that I can't solve and I've tried looking online but can't find anything yet.
I'm using a UIImagePickerController to pick and image and I'm using it in the App Delegate. When an image is returned, in the imagePickerController:didFinishPickingMediaWithInfo method, I want to make a new navigation controller with a view controller and put it over the "app".
Here is how I'm doing it:
CustomNavigationController *customNavigationController = [[CustomNavigationController alloc] init];
PhotoViewController *photoViewController = [[PhotoViewController alloc] initWithNibName:#"PhotoViewController" bundle:[NSBundle mainBundle]];
[customNavigationController pushViewController:photoViewController animated:NO];
[customNavigationController.view setFrame:[[UIScreen mainScreen] applicationFrame]];
[photoViewController release];
[self.window addSubview:customNavigationController.view];
//Call method of photoViewController.
[[customNavigationController.viewControllers objectAtIndex:0] addPhotoFromData:info];
[self.tabBarController dismissViewControllerAnimated:YES completion:nil]; //Get rid of UIImagePickerController
However in the photoViewController, I don't have access to any instance variables synthesized and loaded in viewDidLoad. They all return to null. There is also a tableView and calls to reload the tableView do not actually cause the tableView to respond.
Here is some of the code from photoViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.photoCount = 0;
self.timestamp = [[NSDate date] timeIntervalSince1970];
self.photos = [[NSMutableArray alloc] initWithCapacity:5];
self.photosData = [[NSMutableArray alloc] initWithCapacity:5];
self.uploadingCount = 0;
UINib *customCell = [UINib nibWithNibName:#"CustomTableCell" bundle:[NSBundle mainBundle]];
[self.tableView registerNib:customCell forCellReuseIdentifier:#"customCell"];
self.tableView.separatorColor = [UIColor clearColor];
NSLog(#"%#", self);
}
and also the addPhotoFromData method:
- (void)addPhotoFromData:(NSDictionary *)info
{
[self.photos addObject:info];
NSLog(#"%#", self.photos); //Doesn't add "info" and does not return anything when later called from other methods.
[self.tableView reloadData]; //Doesn't work
Everything was working before I add in the UINavigationController. I'm completely lost.
EDIT: After some more debugging attempts, I have discovered that the view is not loaded when addPhotoFromData is called. viewDidLoad is called afterwords. Is there a way to delay method calls?
Any reason you can't have the PhotoViewController call addPhotoFromData: inside the viewDidLoad method? You can always access properties of the app delegate from the view controller:
YourAppDelegateType * delegate = [UIApplication sharedApplication].delegate;
[self addPhotoFromData:delegate.info];

White screen after presenting a modal view controller

I'm getting a white screen after presenting a modal view controller. This is how I do it:
SomeViewController *controller = [[[SomeViewController alloc] initWithManagedObjectContext:managedObjectContext] autorelease];
UINavigationController *navController = [[[UINavigationController alloc] initWithRootViewController:controller] autorelease];
[navController setModalTransitionStyle:UIModalTransitionStyleCoverVertical];
[self presentModalViewController:navController animated:YES];
The navigation bar works fine, as I set it up in SomeViewController, but the view's contents are not visible, and all I see is the white background color of the root window.
The strange thing is, that this used to work, but now it doesn't for some reason.
What could be the problem?
EDIT:
This is how I create SomeViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
[self setTitle:#"Some View"];
UIBarButtonItem *sortButton = [[[UIBarButtonItem alloc] initWithTitle:#"Sort" style:UIBarButtonItemStylePlain target:self action:#selector(sortButtonClicked:)] autorelease];
[[self navigationItem] setRightBarButtonItems:[NSArray arrayWithObjects:sortButton, [self editButtonItem], nil] animated:YES];
UIBarButtonItem *backButton = [[[UIBarButtonItem alloc] initWithTitle:#"Back" style:UIBarButtonItemStylePlain target:self action:#selector(dismissModalViewControllerAnimated:)] autorelease];
[[self navigationItem] setLeftBarButtonItem:backButton];
// Hack to force landscape orientation
UIViewController *controller = [[UIViewController alloc] init];
[self presentModalViewController:controller animated:NO];
[self dismissModalViewControllerAnimated:NO];
[controller release];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return UIInterfaceOrientationIsLandscape(interfaceOrientation);
}
The white screen was caused by the xib file of the controller not being part of the target(its target membership checkbox was unchecked).
Do you happen to have some other init meted also in the SomeViewController class? Please post the whole .m file. If so, you can try to delete the initWithNibName method and check if it shows the content.
EDIT:
Another strange point is the initWithManagedObjectContext method you are using on the viewController instance. Can you explain it?
try
SomeViewController *controller = [[[SomeViewController alloc] init] autorelease];
it should work fine.

Display UIView subclass which contains other UIViews

I want to package some UIViews suchs as UIButton, UIImageView in a single UIView.
When I try to display that view, it is not showing up on my RootViewController:
Here is the code of my UIView subclass :
#import "Hover.h"
#implementation Hover
- (id)init{
self = [super init];
if (self) {
// Initialization code
UIImage *hover = [UIImage imageNamed:#"Hover.png"];
UIImageView *imageView = [[UIImageView alloc] init];
imageView.image = hover;
imageView.frame = CGRectMake(0, 0, hover.size.width, hover.size.height);
imageView.alpha = 0.75;
[self addSubview:imageView];
[imageView release];
}
return self;
}
And here is the RootViewController class:
- (void)viewDidLoad
{
Hover *hover = [[Hover alloc] init];
[self.navigationController.view addSubview:hover];
[hover release];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
The "hover view" is not displayed! However, when I add a single UIImageView to my RootViewController, it works!
In order for your view to display, you should override the -(id)initWithFrame:(CGRect)frame;, instead of writing a custom initializer.
Try this way :
-(id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if(self) {
// do init here...
}
return self;
}
Also, in the -(void)viewDidLoad; method, first send [super viewDidLoad];, and then alloc/init the view.
- (void)viewDidLoad
{
[super viewDidLoad];
Hover *hover = [[Hover alloc] init];
[self.navigationController.visibleViewController.view addSubview:hover];
[hover release];
// Do any additional setup after loading the view, typically from a nib.
}
Just a quick guess at a glance: If you're using a navigationcontroller, you should initWithRootViewController. You can't add a view to a navigationcontroller directly, Use push instead.
HTH
Marcus