Replace PlaceHolder View With other ViewControllers leads to Thread 1:EXC_BAD_ACCESS Code 1 - objective-c

hey guys created a custom segue tab bar, using this guys tutorial,
http://www.scott-sherwood.com/tutorial/ios-5-creating-a-custom-side-tabbar-using-storyboards-and-custom-segues/
after trying to figure out why why my app doesn't work, i realised that the technique i was using was about replacing the existing view with the linked ViewController as a subview.
////////////////////////////////////////// the over-written perform method as follows /////////////////////////
-(void) perform {
ViewController *src = (ViewController *)[self sourceViewController];
UIViewController *dst = (UIViewController *) self.destinationViewController;
for (UIView *view in src.placeholderView.subviews ) {
[view removeFromSuperview];
}
src.currentViewController = dst;
[src.placeholderView addSubview:dst.view]; }
////////////////////////////////////////////// /////////////////////// /////////////////////// ///////////////////////
now once i am on the linked ViewControllers i was hoping to add another link to another ViewController which would hold the Editing functions for the information each respective pervious ViewControllers. Now when i try to connect a the ViewControllers via any Segue the app crashes and give me a Thread 1:EXC_BAD_ACCESS. When i use NSZombie its give me this in the console,
[UIStoryboardSegueTemplate performSelector:withObject:withObject:]: message sent to deallocated instance 0x7c3a4d20
no i understand what is happening in theory, the viewController is trying to ad the next one to an empty space (i think the entire placeHolder has been deleted thus giving the viewController nowhere to go) i think, i was wondering if anyone could help with this i mean i a have been looking everywhere for a solution but i keep getting the same error.
i even created a VieController class for the ProfileViewController.m/ProfileViewController.h in which i add
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
if([[segue identifier] isEqualToString:#"ProfileEditSegue"]){
ProfileViewController *cvc = (ProfileViewController *)[segue destinationViewController];
[cvc.placeholderView addSubview:cvc.view];
}
}
this to leads me to the same errors. I will be glad to send anyone my source files, the same error occurs when i do it on the supplied files from the tutorial.
PS. i am using this method so that i can have a vertical navigation bar, but i want to do it simply so i could also learn how one works and be able to use/develope it further.
any help would be great

The problem wasnt in those methods it was because the currentViewController instances was set to weak instead of strong

Related

Presenting correct View Controller instance depending on cell selection in UITableView

I understand this might be covered in parts in answers to other questions (see references) I've seen on the site, but due to my limited experience I haven't been able to understand each part as it relates to my code. Please forgive me for any duplications.
I have a PFQueryTableViewController (essentially a UITableViewController) called threadsViewController that sources cell information from a Parse backend. The table view consists of threads similar to what you would see on a web forum.
I then have a separate class postsViewController which is another PFQueryTableViewController that I wish to display a table of all the responses ('posts') to that particular thread.
The functionality I'm looking for is for a user tapping on a thread (left screen in the image) to be presented with a postsViewController (right screen) containing only those posts/responses related to that thread. (See basic diagram below).
What I do know from my research:
The Parse backend is established with classes for Thread and Post.
I'm probably going to use the didSelectRowAtIndexPath delegate method
What I need help with:
How can I know which thread cell a user tapped on, and then pass that on so that the postsViewController only displays posts from that Thread?
A layman's description of how to use indexPath.row etc
I understand how to complete PFQueries etc to get the data for the cells, I just don't know how to implement the navigation and how to tell postsViewController which posts to show.
In case it helps somehow, here is my implementation so far. I have tried addign a property to the postsViewController called fromThread to somehow store the thread but apart from that I'm out of ideas!
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
postsViewController *postsVC = [[postsViewController alloc] init];
postsVC.fromThread = //?
[self performSegueWithIdentifier:#"threadsToPosts" sender:self];
}
References
How to filter a Parse query by an tableview index?
Pass Index Number between UITableView List segue
didSelectRowAtIndexPath and prepareForSegue implementation
You're on the right track. You need know how to do two things: (1) access your parse objects by indexPath, and (2) push a new view controller in a navigation controller.
(1) is simpler: PFQueryTableVC provides a method called objectAtIndexPath: that does just what you need.
// indexPath is the indexPath parameter to the didSelectRow delegate method
PFObject *fromThread = [self objectAtIndexPath:indexPath];
(2) is simple, too. But more complicated because there are a couple ways to do it. Segue is the more modern way, but I think the old way is simpler, and certainly easier to describe in code. View Controllers are given storyboard ids on the "Identity" tab in the storyboard editor. Give your Posts-presenting VC a storyboard id like "PostVC".
To get a new instance, use that storyboard id as follows:
MyPostVC *postVC = [self.storyboard instantiateViewControllerWithIdentifier:#"PostVC"];
// initialize it with the PFObject we got above
postVC.fromThread = fromThread;
// present it on the navigation stack
[self.navigationController pushViewController:postVC animated:YES];
And fromThread is just what the PostVC will need to form a query for posts associated with the selected thread.
You can pass data of cell to next ViewController in prepareForSegue with something like this
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"threadsToPosts"]) {
UINavigationController *navCon = segue.destinationViewController;
postsViewController *postsViewController = [navCon.viewControllers objectAtIndex:0];
// Whatever you are populating your tableView with
Thread *thread = [self.thread objectAtIndex:self.tableView.indexPathForSelectedRow.row];
postsViewController.thread = thread;
}
}

Undeclared identifer error in prepareForSegue : using Storyboards in iOS6

I am trying to build a 2 scene application using Storyboards in iOS6.
I am taking the users name via text input in the first scene and passing it using a push segue to the second scene; where it is displayed in a label.
The first scene's UIViewController is called ViewController and the second scenes UIViewcontroller is DrawViewController.
I have imported the the DrawViewController.h in my ViewController.m file where I have defined the prepareForSegue as below:
-(void) prepareForSegue:(UIStoryboardSegue *) segue sender:(id) sender{
if ([segue.identifier isEqualToString:#"ColorPickerControllerSegue"]){
DrawViewController *dvc =[segue destinationViewController];
dvc.userName= self.userName;
}
}
Here userName is a NSString defined in DrawViewController.
I am getting "use of undeclared identifer:DrawViewController".
I am quite new to iOS programming, so is there something I am missing here?
I have set the second view controller's custom class to DrawViewController.
I was able to solve this issue by removing the existing DrawViewController.h and DrawViewController.m files and then creating and adding them back to the the project.
It seemed to do the trick.

How to Properly Switch Between Views

I'm making an iOS app (first actual app that isn't Hello World), and it will have 2 screens. I asked on here before how to make one screen (or View Controller) open another, and this is what I figured out to use:
[self presentViewController:[[self storyboard] instantiateViewControllerWithIdentifier:#"statView"] animated:YES completion:nil];
It works. However, it gives me the following message when this runs:
Unknown class statView in Interface Builder file.
(Note: this doesn't stop me from using the app, it just seems to be a warning.
This leads me to believe I'm doing something wrong. Also, it seems I'm instantiating this new view controller, but never getting rid of it. So when I go back and forth, I imagine I might be leaving these View Controllers instantiated as new every time?
So my question is:
If there is a better way to switch between these windows, how can it be done?
If this is correct, why the error message?
The most easy way is unsing the Storyboard.
Add a button and link it to the second view.
You can use a Segue to parse data:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if([[segue identifier] isEqualToString:#"SEGUENAME"]) {
SecondViewController *secondViewController = [segue destinationViewController];
secondViewController.parameter = parameter; // Parse a value
}
}

Objective-C (iOS): prepareForSegue won't pass my data into destination VC

VC1 = NewGameViewController
VC2 = GameViewController
NewGameViewController.m
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if( [segue.identifier isEqualToString:#"newGameSegue"]) {
GameViewController *gameVC = (GameViewController *)segue.destinationViewController;
NSArray *array = [self nameArrayForTextFieldArray:self.namePicker.textFieldArray withColon:YES];
gameVC.nameArray = [[NSArray alloc] initWithArray:array];
}
-(NSArray *)nameArrayForTextFieldArray:(NSArray *)array withColon:(BOOL *)bool
basically returns an nsarray of strings given an nsarray of textfields. withcolon is a bool of whether or not you want the strings to have a colon appended to the end.
when i debug my code, the _nameArray ivar in gameVC still reads nil after every line here is called...can anyone help me out here??
The prepareForSegue method is invoked by UIKit when a segue from one screen to another is about to be performed. It allows us to give data to the new view controller before it will be displayed. Usually you’ll do that by setting its properties.
The new view controller can be found in segue.destinationViewController. If GameViewController embed the navigation controller, the new view controller will not be GameViewController but the navigation controller that embeds it.
To get the GameViewController object, we can look at the navigation controller’s topViewController property. This property refers to the screen that is currently active inside the navigation controller.
To send an object to the new view controller you can use this solution using performSegueWithIdentifier:
For example, if we want to perform a segue pressing a UIButton we can do this:
In the MyViewController.h we create a IBAction (connected to UIButton), dragging the button from storyboard to code:
- (IBAction)sendData:(id)sender;
In MyViewController.m we implement the method:
- (IBAction)sendData:(id)sender
{
NSArray *array = [self nameArrayForTextFieldArray:self.namePicker.textFieldArray withColon:YES];
[self performSegueWithIdentifier:#"newGameSegue" sender:array];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"newGameSegue"]) {
UINavigationController *navigationController = segue.destinationViewController;
GameViewController *controller = (GameViewController *)navigationController.topViewController;
controller.nameArray = sender;
}
}
Is GameViewController embedded in a navigation controller? In that case, your destinationViewController property is of type UINavigationController, not GameViewController. You can get to GameViewController by calling [segue.destinationViewController.viewControllers lastObject].
I'm assuming that you've done a NSLog (or examine it in the debugger) of array immediately before setting gameVC.nameArray. You really want to make sure it's being set the way you think it is. It's amazing how many times I've spent debugging something like this only to realize the problem was in my equivalent to nameArrayForTextFieldArray. Or a typo in the name of the segue identifier. Or random things like that.
Assuming that's ok, then a couple of things are possible:
How is your nameArray property defined in GameViewController? If it's not a strong reference (or a copy), then when your array falls out of scope, it will be deallocated. I think this would manifest itself slightly differently, but it's worth confirming.
Also, I've seen situations where a controller like GameViewController might have some confusion between various ivars and properties (which is why I never define ivars for my properties ... I let #synthesize do that).
I assume you're not using a custom setter for nameArray. I just want to make sure. If so, though, please share that, too.
Bottom line, can you show us all references to nameArray in your #interface of GameViewController as well as in its #synthesize statement?

Simple Passing of variables between classes in Xcode

I am trying to do an ios app but I am stuck at passing data between classes .
This is my second app . The first one was done whit a global class , but now I need
multiple classes . I tried many tutorials , but did not work or the passed value was always zero . Can someone please write me a simple app to demonstrate passing of variables in IOS 5 .
Nothing special , storyboard whith 2 view controllers , one variable .
Thank you for your help .
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// Navigation logic may go here. Create and push another view controller.
FirstViewController *fv;
fv.value = indexPath.row;
NSLog(#"The current %d", fv.value);
FirstViewController *detail =[self.storyboard instantiateViewControllerWithIdentifier:#"Detail"];
[self.navigationController pushViewController:detail animated:YES];
}
here is the code from my main view and i need to send the indexPath.row or the index of the cell that i pressed to the next view
There are several things to do. Depending on the app, you could either add a variable to the AppDelegate class, making it availible to all classes through a shared instance. The most common thing (I think) is to make a singleton. For that to work, you can make a class, say StoreVars, and a static method that returns the object, which makes the class "global". Within the method, you initialize all your variables, like you always would. Then you can always reach them from wherever.
#interface StoreVars : NSObject
#property (nonatomic) NSArray * mySharedArray;
+ (StoreVars*) sharedInstance;
#implementation StoreVars
#synthesize mySharedArray;
+ (StoreVars*) sharedInstance {
static StoreVars *myInstance = nil;
if (myInstance == nil) {
myInstance = [[[self class] alloc] init];
myInstance.mySharedArray = [NSArray arrayWithObject:#"Test"];
}
return myInstance;
}
This will make a singleton. If you remember to import "StoreVars.h" in your two viewControllers, you can access the now shared array like this;
[StoreVars sharedInstance].mySharedArray;
^
This is a method returning a StoreVars object. Within the StoreVars class, you can implement any object and initialize it in the static method. Just always remember to initialize it, or else, all your object will be 0/nil.
If you are not a fan of the UINavigationController and would rather use segues, it's a lot easier, but can make your app rather "messy" imo. There is a method implemented in UIViewController you should overload:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object];
}
}
source: How to pass prepareForSegue: an object
Do some research before asking questions like this. Read some tutorials, and try out yourself, and then ask questions related to what you are really looking for. It's not everyday people want to do all the work for you, but sometimes you're lucky. Like today.
Cheers.
if you use segue between 2 controllers you must overload prepareToSegue method
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// check if it's the good segue with the identifier
if([[segue identifier] isEqualToString:#"blablabla"])
{
// permit you to get the destination segue
[segue destinationViewController];
// then you can set what you want in your destination controller
}
}
The problem you face is quite perplexing for beginners. "Solving" it wrong way can result in learning a ton of bad habits.
Please have a look at Ole Begemann's excellent tutorial on Passing Data Between View Controllers - it's really worth reading.