i am integrating twitter app in my iOS app.the problem is on login when it return to my iOS app the segue which i want to perform is not performing visually, means the transition from one view controller to another is not visible but prepareForSegue method is being called and i can see that in my output console.
my twitter login method is as follow:
- (IBAction)tweetbutton:(id)sender {
[SCTwitter initWithConsumerKey:#"your_consumer_key" consumerSecret:#"your_consumer_secret"];
[SCTwitter loginViewControler:self callback:^(BOOL success){
NSLog(#"Login is Success - %i", success);
if (success) {
[self performSegueWithIdentifier:#"authentication" sender:self];
}
}];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
NSLog(#"prepareForSegue: %#", segue.identifier);
}
the output in console is:
2014-12-10 23:54:16.923 gems[1300:60b] Login is Success - 1
2014-12-10 23:54:16.946 gems[1300:60b] prepareForSegue: authentication
i don't understand where i am wrong and why segue is not performing visually.please suggest a suitable solution and also for your knowledge i am using plain view controller and not navigation controller.
thanks in advance.Any help would be appreciated.
Make sure you have a segue called "authentication" wired up correctly. You can check that by setting a breakpoint in prepareForSegue:sender: method and examine the segue.destinationViewController object.
Related
I've encountered something that I've never seen. The scenario is as follows. My initial VC has an enroll button that when hit bring up a couple of separate view controllers deal with the enrollment procedure (I ask for user credentials, and if required by the server, I ask for a verification code). When this process is complete, I save a custom object to NSUserDefaults that is needed later. Then the initial VC is shown again.
Basically, I'm making sure I'm in the main thread and that the custom object is saved. If those conditions are met, I then push the main part of the app.
Here is the relevant code, all my logs are displayed in the output window, but the segue does not happen.
- (void)viewDidLoad {
[super viewDidLoad];
self.complete = false;
if([NSThread isMainThread]){
NSLog(#"Main Thread-Yes");
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"CUSTOMOBJECT"]) {
NSLog(#"Will begin pushToAuthenticate");
[self pushAuthenticateController];
}
} else {
NSLog(#"Main Thread-No");
}
}
- (void)pushAuthenticateController{
[self performSegueWithIdentifier:#"pushMainVC" sender:self];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"pushMainVC"]) {
NSLog(#"PrepareForSegue-pushMainVC");
[segue.destinationViewController.navigationItem setHidesBackButton:YES];
[segue.destinationViewController.navigationItem setTitle:#"MainVC"];
}
}
In storyboard I have a segue that connects the initial VC with the MainVC, the identifier for that segue matches "pushMainVC", and if I close and reopen the app (after enrolling) the segues does occur. The console output for both instances (reloading the initial VC after enrolling and closing and reopening the app) are as follow:
APPNAME[4106:1628238] Main Thread-Yes
APPNAME[4106:1628238] Will begin pushToAuthenticate
APPNAME[4106:1628238] PrepareForSegue-pushMainVC
Any idea why this could happen, any small thing I'm missing, or any help will be greatly appreciated. Thank you so much.
You are attempting to perform a push segue from viewDidLoad. But you can't do that because it's too soon; viewDidLoad means that the view exists but is not yet in the interface. You need to wait until there is an interface so you have something to push from.
You cant try to load it from the storayboard itself.
like this:
pushMainVC* pushMainV = [self.storyboard instantiateViewControllerWithIdentifier:NSStringFromClass([pushMainVC class])];
[self.navigationController pushViewController:pushMainV animated:YES];
NOTICE:
Dont forget to give your viewcontroller Storyboard ID.
I have a button in a cell which calls a protocol that has data that needs to be passed to the view controller by the segue. The segue is happening through storyboard. My current code uses the shouldperformsegue to return no when the button is pressed as the first segue that happens does not have the data.
Im guessing the segue and the protocol are being handled asynchronously.
But before I return NO I tell it to perform the segue at a delay. This delayed segue does have the data and works fine.
My question is there a way to wait for the protocol to finish and then perform the segue? Maybe with an execution block?
The other responders have hinted about this, but haven't stated it explicitly, so here goes.
Do not tie a segue directly to the button. Instead, control-drag from the source view controller SCENE to the destination scene to create a segue at the view controller level. Give the segue a unique identifier.
Then, in your button IBAction code, do the async network download. You may want to display a "loading, please wait" message or something while the download is taking place. Most async network calls take a completion block. In that completion block, wrap a call to performSegueWithIdentifier in a call to dispatch_async(dispatch_get_main_queue() so the segue gets invoked on the main thread. (#SantaClaus's answer shows the syntax for that.)
So your button IBAction code might look like this:
- (IBAction) buttonAction: (UIButton *) sender;
{
//Display a "please wait"message to the user if desired
doAsyncCallTakingBlock( completion: ^(NSData *data)
{
//parse the data, (or whatever)
dispatch_async(dispatch_get_main_queue(), ^
{
//This call uses the button as the sender. That might be appropriate,
//or not.
[self performSegueWithIdentifier:#"jumpToOtherViewController"
sender: sender];
});
}
}
With this approach the segue doesn't get called until the async method (Which I called doAsyncCallTakingBlock in my example code) has finished it's work. You might call an Alamofire request method, use an NSURLSession, or any other async method that takes a completion block.
Yes, I would use blocks. For example:
[Api getDataWithCompletion:^(BOOL success, NSString *data) {
if (success) {
self.data = data;
[self performSegueWithIdentifier:#"MySegue" sender:self];
} else {
NSLog(#"Failed to get data");
}
}];
Then, to pass it to the next view controller:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"MySegue"]) {
TargetViewController *targetVC = (TargetViewController*)segue.destinationViewController;
targetVC.data = self.data;
}
}
Check out performSegueWithIdentifier on UIViewController. If you set up a segue between the view controllers in your storyboard (not from the button) and give it an identifier, you can perform the segue as soon as the data is ready.
Since you mentioned that your data is being fetch asynchronously, you might need to dispatch the performSegueWithIdentifier call to the main thread like so:
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"jumpToOtherViewController" sender:self];
});
To actually pass the data on to the next view controller, you can use prepareForSegue as described here.
I am attempting to perform a segue after a done button is pressed from a custom signature alertView. The segue works perfect if I call it from a button inside the same view, but when I call from my signature class, I get a crash that says:
`'Receiver (<SuperSigApproveTableViewController: 0x79eea280>) has no segue with identifier 'approveSwap''
SignatureAlertViewController is the name of the class that calls the done method
- (IBAction)dismissAlertView:(id)sender {
[linerSig sendSigImageToServer];
[self.presentingViewController dismissViewControllerAnimated:YES completion:^{[sp sendToPDF];}];
}
inside the completion block is the method I am trying to call which is located inside of SuperSigApproveTableViewController
-(void)sendToPDF {
NSLog(#"sendtopdf");
[self performSegueWithIdentifier: #"approveSwap" sender: self];
}
I have alloc and init the SuperSigApproveTableView in the viewDidLoad method of SignatureAlertViewController. I am not sure why it is crashing does anyone have any clues?
Using Parse, after I'm logged in I am presented PFQueryTableViewController that displays a list of tasks and another detail view controller that allows me to edit the task detail and segue back. The issue right now is that the PFQueryTableViewController does not reflect the new changes after I finished editing and popping the task detail view off the stack. However the table view list does get updated when I go back to the login screen(view before the PFQueryTableViewController) and re-enter the table view again. I've tried the following:
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self.tableView reloadData];
}
and also
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
[self loadObjects];
[self.tableView reloadData];
}
Yet they don't seem to take effect. My guess is that the data is updated after the view is popped off and the table view appears. I'm just wondering if anyone has any insight on this while I'm investigating. Thanks!
You could try re-querying the queryForTable method in viewDidAppear (this would naturally use an API request on every view appearance however)
- (void)viewDidAppear:(BOOL)animated {
[self queryForTable];
}
This answer assumes that you are using Local Datastore and want to see changes made in it be reflected in a PFQueryTableViewController.
Because the ParseUI classes do not implement any form of caching though the local datastore, changes made in the detail view will not appear in the PFQueryTableViewController until the save operation has completed and the tableView has fetched the new items from Parse.
One solution to your problem would be adding a category to the PFQueryTableViewController that modifies how it fetches data to include what is in the Local Datastore as well.
You should make sure the data is saved before popping your view controller.
Use Parse's save method with completion handler.
[request saveInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (succeeded) {
[self.navigationController popViewControllerAnimated:YES];
}
}];
You can use [self loadObjects] to trigger a refresh for all objects in the PFQueryTableViewController.
I have never had this problem before or heard of it happening. I am using a Master-Detail Application (splitview) for the ipad. I have a dynamic tableview for my MVC and am trying to transition each cell to a custom view controller.
Currently I only have two items in my table. When the program boots I can select either of them and it will transition to the correct view controller without any problems. But most of the time when I click on something a second time the program crashes. Sometimes it takes four or five clicks but it always eventually crashes.
Here is the code snippet:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *segueName = [self.tableObjects objectAtIndex:indexPath.row];
[self performSegueWithIdentifier:segueName sender:self];
}
tableObjects is an NSArray that I use to create the table items. If I throw a print statement in before the segue call it does print the correct segue name.
The error is always being thrown on the actual performSegueWithIdentifier call. I checked it with the debugger. The exception I keep getting is: EXC_BAD_ACCESS.
Again both of the segues work initially so I do not think it is a problem with this. Does this method sometimes get called randomly? Is there a way to double check that the method call is safe? Do I need to override performSegueWithIdentifier and do something there?
I attempted to put it into a try catch:
#try {
[self performSegueWithIdentifier:segueName sender:self];
}
#catch (NSException *exception) {
NSLog(#"%#", exception);
}
#finally {
NSLog(#"finally");
}
and it still pointed to the method call inside of the #try. It does not seem to be throwing the error like an exception?
FYI, I was running into this exact same issue, and I found the answer on another SO thread: iOS - UISplitViewController with storyboard - multiple master views and multiple detail views
Basically, the uisplitviewcontroller delegate needed to be set again when making the segue. Hope this helps someone in the future.