Trying to use performSegueWithIdentifier to segue to ViewController after connectionDidFinishLoading is finished - objective-c

I have two viewcontrollers mainVC and drop_downVC. I also have an object called JSONutils. The user will enter input into a textfield in the mainVC viewcontroller and methods are then used in the JSONutils to contact a RESTful api and a JSON object is then returned and parsed. I'd like to segue to the drop_downVC viewcontroller when the connectionDidFinishLoading method in JSONutils completes. Everything is working up to the point of trying to segue to the drop_downVC. From the research I've been doing it seems using the performSegueWithIdentifier is the way to go. So below is the code that I'm trying to implement in the connectionDidFinishLoading method in JSONutils.
//JSONutils.m
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
//NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
//NSLog(#"The receivedData is: %#", receivedData);
//JSON parsing code from here to
//here...
[self performSegueWithIdentifier:#"segue_drop_downVC" sender:self];
}//(void)connectionDidFinishLoading
the above code gives me the following error.
No visible #interface for 'JSONutils' declares the selector 'performSegueWithIdentifier:sender:'
I've googled this error but can't find anything that applies to my specific solution.
I created the segue and named the segue identifier appropriately (segue_drop_downVC) using this post.
I've also been putting the following code anywhere (JSONutils, mainVC) possible to see if that would change anything but it hasn't.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
//NSLog(#"The segue identifier is: %#", [segue identifier]);
//if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
drop_downVC *nextViewController = [segue destinationViewController];
}
I don't have much experience programming in Objective-C but when I have I've used storyboard and segue to move between viewcontrollers. When I have used storyboard and segues I've "segued" when the user hit a button. I've never had to wait for data to come back and then navigated to the next viewcontroller. My plan is continue to put all of my JSON manipulating and parsing methods in the JSONutils files. So I'd like to keep those type of methods out of mainVC and drop_downVC. I've been doing research, trying different things but can't seem to get it. Any help or feedback is greatly appreciated! Thanks.

The performSegueWithIdentifier is a method of the UIViewController class, so if your JSONUtils class is not a subclass UIViewController, you cannot send that message to self. That's what the error says.
The same applies to prepareForSegue.
To solve your problem, there are several alternatives. Maybe the simplest one is to use delegates.

You need to call performSegueWithIdentifier from your view controller, not JSONutils. I think the way to do this is to create a delegate protocol in JSONutils and have the MainVC set itself as delegate when it creates an instance of JSONutils. Call the delegate method from connectionDidFinishLoading:

Related

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

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

How do I find a pointer to a segue (without calling one of the performSegue methods)?

From within one of my tableViewControllers I need to get a pointer to another tableView (which is the destination of the segue from this tableViewController). I don't actually want to perform the segue and pull up the new view onto the screen, i simply need a pointer to the destinationViewController.
The only place i can seem to find a pointer to this object is through one of the performSegue methods...
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
SavedTrackingViewController *stvc = (SavedTrackingViewController*) segue.destinationViewController;
But i cant seem to find a pointer to this segue anywhere else in my view controller.
Any help would be appreciate!

UIViewController throwing unrecognized selector exception on prepareForSegue

I'm trying to follow along the Stanford CS193p iOS programing lectures. One of the demo programs, called "Happiness" creates two UIViewControllers, a "PsychViewController" and a "HappinessViewController." It segues from the PsychViewController to the HappinessViewController using a target action method.
The following code keeps throwing this exception: "-[UIViewController setHappiness:]: unrecognized selector sent to instance"
Here's the offending code:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"ShowDiagnosis"]) {
[segue.destinationViewController setHappiness:7];
}
}
I have searched this site and others, and the usually when this error comes up, it is because the generic UIViewController has not been correctly set to the specific view controller object used in the program, in this case the "HappinessViewController." But I have set the generic UIViewController to be a HappinessViewController using the identity inspector in IB, and I am still getting the exception. I am tearing my hair out, if anyone could help it would be much appreciated.
Let's look at the exception:
-[UIViewController setHappiness:]: unrecognized selector sent to instance
This tells you two things about the message that was unrecognized. It tells you the selector, setHappiness:. It also tells you the actual, runtime class of the receiver, UIViewController.
Of course, UIViewController has no method named setHappiness:. That's why you got the exception.
You wrote a subclass of UIViewController called HappinessViewController which does have a setHappiness: method (or a read/write property named happiness, which generates the method). And you intended for the receiver (the destination view controller) to be an instance of that subclass (HappinessViewController).
But the exception is telling you that the destination view controller is just a plain UIViewController. So even though you think you did, you probably did not set the view controller's custom class in the storyboard. Maybe you set the custom class of some other view controller, but you didn't set the class of this segue's destination.
You need to set the destination view controller's custom class in the Identity Inspector, like this:
I figured out the problem. Although I had correctly specified that the relevant UIViewController was a HappinessViewController, the linker, was for some reason, not linking to the correct files. The fix was to go to double click on the .xcodeproj file inside Xcode, then go to Build Phases and manually add the files under "Compile Sources."
For me changing the class of the view controller in the story board worked.
Try like this:
HappinessViewController *controller = segue.destinationViewController;
[controller setHappiness:7];
I had the same problem today and it was because my custom class was in a library. The library itself was being linked in build phases, but that in itself was not enough to pull in the class. So finally I solved it by add the following line to my AppDelegate.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
[ CustomClass class ];
}
This forces the linker to pull in the class. Otherwise simply linking in the library may not be enough to pull in the class unless it is referenced somewhere in the application.
I tried adding a Cast and it worked for me, I had the same problem:
FirstViewController *detailViewController =
(FirstViewController *)[segue destinationViewController];
Check which prepareForSegue is triggering. My problem was that 2 segues were triggering, in the current viewController and in the incoming viewController. The solution, and always a good practice is to check segues identifiers.
- (void)prepareForSegue:(UIStoryboardSegue*)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"segueIdentifier"]) {
}
}
Cast before assigning
HappinessViewController *controller = (HappinessViewController *)segue.destinationViewController;
[controller setHappiness:7];
Make sure in your storyboard, HappinessViewController is set as the class of you VC

Class instances differ, which one to use?

I'm stuck with the following. In a program, I'm trying to communicate between different classes (View Controllers with NIB files attached in a TabBar application etc). I want to call a method 'OMFG' in a class called 'ProductViewDetailController'. This class is a UIViewController (SplitViewDelegate). It's loaded programmatically.
Anyways, I've been trying to get the right call to this controller, and I came up with 2 solutions. One is declaring the productviewdetailcontroller in the caller's .h file and .m file, making an IBOutlet, linking it in the Interface builder and calling it directly by the line
[productDetailController OMFG];
When I call this method, it calls the right method in the ProductViewDetailController, but the instance of this viewcontroller differs from the one I programmatically can reach with this code:
for (UIViewController *controller in self.tabBarController.viewControllers) {
NSLog(#"%#", [controller class]);
if ([controller isKindOfClass:[UISplitViewController class]]) {
UISplitViewController *cell = (UISplitViewController *)controller;
for (UIViewController *controller2 in cell.viewControllers) {
NSLog(#"%#", [controller2 class]);
if ([controller2 isKindOfClass:[ProductViewDetailController class]]) {
[controller2 OMFG];
}
}
}
Which one should I use, and why?
edit: When I try to add a SubView to both viewcontrollers, the one where the call is [controller2 OMFG]; actually shows the newly added view, where the [productDetailController OMFG]; doesn't show the newly added view... Why is that? Is there a shorter (and more chique) way to get access to the right ViewController?
You should use a IBOutlet. This makes sure your app can still call the correct target if you later decide to change the hierarchy of view controllers, for example if creating an iPhone compatible setup without a UISplitViewController.
Calling isKindOfClass: in Objective-C is a sure sign that what you are doing is probably wrong. Firstly in Cocoa Touch what you do is always more important than who you are. Secondly what you try to do is probably peeking inside something that should be left private.

objective-c: Calling a void function from another controller

i have a void, like -(void) doSomething in a specific controller.
i can call it in this controller via [self doSomething], but i don't know how to call this void from another .m file.
I want to call it in a -(IBAction) action:(id)sender
I've tried using performSelector, but i got a 'unreconiezd selector send' in the log.
I've no idea if i have to use the notification center, or delegate...
Thanks,
ronan.
You have to have an instance of the first controller (the one where you declare the function in) in your second controller.
FirstViewController *firstController = [[FirstViewController alloc] init];
[firstController doSomething];
If your first controller is declared somewhere else, and you want your second controller to know about it, have a property of FirstViewController type in your second controller, and initialize it when you need it with your FirstViewController instance.
Sometimes, this can be quite complicated to do if you have multiple controller instances and you want every one of them to know about all the others, so I would rather suggest rewriting your method to a class method:
+ (void) doSomething;
so you could call it from anywhere with
[FirstViewController doSomething];
if you have the object you want to call it on and the method is public, then you just:
[object doSomething];
The problem is that you have two controllers who don't know about each other's existence. The notification center certainly is the way to deal with this situation: the advantage is that you need not establish a formal connection between the two.
The delegate method is another possibility, but then you have to either establish the connection via an IBOutlet in Interface Builder, or you must have one controller create the other controller and pass itself as the delegate. This ties them together more closely, which may or may not be appropriate. If the only connection between the two controllers is the calling of one -(void) method, then I'd go with NSNotification.