I have a table view with different information the user can update. One of them is "pilot information". When the user clicks on this row they are taking to another view controller where they fill out information on the pilot. (name phone number etc)
They can then hit save or cancel both of which return them to the previous table view controller. What I want to do is have the user be able to click on pilot information again, and view the data they just entered and edit it if they choose. My solution to this was to add another segue and give it a unique identifier using the following code. (pilot is the name of the entity in my core data model, updatepilot is the name I gave the segue.)
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"UpdatePilot"]) {
NSManagedObject *selectedPilot = [self.pilots objectAtIndex:[[self.tableView indexPathForSelectedRow] row]];
PilotViewController *destViewController = segue.destinationViewController;
destViewController.pilot = selectedPilot;
}
}
!http://tinypic.com/r/2ihbera/8
However, I get the error use of undeclared identifier 'destviewcontroller" did you mean UIViewController? Is there something I'm not seeing here? any help would be appreciated!
#import "PilotViewController.h"
#interface PilotViewController ()
#end
#implementation PilotViewController
- (NSManagedObjectContext *)managedObjectContext {
NSManagedObjectContext *context = nil;
id delegate = [[UIApplication sharedApplication] delegate];
if ([delegate performSelector:#selector(managedObjectContext)]) {
context = [delegate managedObjectContext];
}
return context;
}
#synthesize pilot;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
if (self.pilot) {
[self.nameField setText:[self.pilot valueForKey:#"pilotName"]];
[self.emailField setText:[self.pilot valueForKey:#"pilotEmail"]];
[self.phoneField setText:[self.pilot valueForKey:#"pilotPhone"]];
[self.insuranceField setText:[self.pilot valueForKey:#"pilotInsurance"]];
}
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//Code created for cancel and save buttons
- (IBAction)cancel:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
- (IBAction)save:(id)sender {
NSManagedObjectContext *context = [self managedObjectContext];
if (self.pilot) {
// Update existing Pilot
[self.pilot setValue:self.nameField.text forKey:#"pilotName"];
[self.pilot setValue:self.phoneField.text forKey:#"pilotPhone"];
[self.pilot setValue:self.insuranceField.text forKey:#"pilotInsurance"];
[self.pilot setValue:self.emailField.text forKey:#"pilotEmail"];
} else {
// Create a new pilot
NSManagedObject *newPilot = [NSEntityDescription insertNewObjectForEntityForName:#"Pilot" inManagedObjectContext:context];
[newPilot setValue:self.nameField.text forKey:#"pilotName"];
[newPilot setValue:self.phoneField.text forKey:#"pilotPhone"];
[newPilot setValue:self.insuranceField.text forKey:#"pilotInsurance"];
[newPilot setValue:self.emailField.text forKey:#"pilotEmail"];
}
NSError *error = nil;
// Save the object to persistent store
if (![context save:&error]) {
NSLog(#"Can't Save! %# %#", error, [error localizedDescription]);
}
[self dismissViewControllerAnimated:YES completion:nil];
}
#end
Try casting the segue.destinationViewController (which is type id) to PilotViewController.
PilotViewController *destViewController = (PilotViewController *)segue.destinationViewController;
In previous versions of Xcode I believe I saw this as a warning; your build settings may be set to treat all warnings as errors.
Related
I have a singleton class, and I have a property declared in it:
#property (nonatomic, strong) NSString *currentTableName;
+ (SuperNoteManager*)sharedInstance;
.m file:
+ (SuperNoteManager*)sharedInstance
{
static SuperNoteManager *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[SuperNoteManager alloc] init];
});
return _sharedInstance;
}
When I run my app for the first time, there is no data in the data base,so it shows the EmptyViewController.
#property (nonatomic, strong) SuperNoteManager *myManager;
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
_myManager=[SuperNoteManager sharedInstance];
}
-(void)changeRootView{
UIStoryboard *storyboard=[UIStoryboard storyboardWithName:#"Main" bundle:nil];
HomeViewController *hVC=[storyboard instantiateViewControllerWithIdentifier:#"HomeViewController"];
UINavigationController *mNavVC=[storyboard instantiateViewControllerWithIdentifier:#"MainNavigationController"];
mNavVC.viewControllers=#[hVC];
[[UIApplication sharedApplication].keyWindow setRootViewController:mNavVC];
}
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if ( [_myManager checkForDataInAllTables]) {
NSLog(#"All tables are empty");
}else{
//a note is saved, show home view controller
if (![_myManager isDatabaseEmpty]) {
[self changeRootView];
}
}
}
There is + button on NavigationBar on EmptyNotesViewController, and on tap '+',
NotesViewController is pushed from EmptyNotesViewController.
In the NotesViewController, after I write some notes, I save the notes in database:
NotesViewController:
#property (nonatomic,strong) SuperNoteManager *myManager;
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
_myManager.currentTableName=#"WorkTable";
}
-(void)viewWillDisappear:(BOOL)animated{
[super viewWillDisappear:animated];
if (self.isMovingFromParentViewController) {
NSLog(#"going back");
[self insertTextintoDatabase]; //Text is inserted . I double checked
}
}
And then When I go back to my EmpytNotesViewController, I check for data, and if data is present, I change the rootViewController as it is not EmptyNotesView anymore.
So When I go back to my EmptyNotesViewController:
-(void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
if ( [_myManager checkForDataInAllTables]) {
NSLog(#"All tables are empty");
}else{
//a note is saved, show home view controller
//Put a breakpoint here
if (![_myManager isDatabaseEmpty]) {
[self changeRootView];
}
}
}
Here at the breakpoint _myManager.currentTableName is nil. why?
I set it in the NotesController, and it became nil when it come back to the EmptyNotesController.
I thought once a value is set in singleton, it will persist as long as the app is closed/killed.
Note: I have declared the property of my Singleton class as strong and also all the properties in the singleton are declared as strong.
It appears like you never get a reference to the SuperNoteManager singleton in NotesViewController, like you did in your EmptyNotesController.
Therefore the currentTableName property never gets set in the first place.
You want to insert:
_myManager = [SuperNoteManager sharedInstance];
in your -viewDidAppear: before you set the currentTableName property.
I have two views :
View1 (Shop) : URL stocked in NSString for displaying image.
View2 (ModifyShop) : Text field with URL from view1.
I can pass data from view1 to view2 : The URL stocked in NSString appears in Text field.
Now I would like to modify this URL with Text field from view2 and that modify the NSString in view1. How can I make that ?
Here is my code :
Shop:
- (void)viewDidLoad {
[super viewDidLoad];
[self.modifyButton setHidden:YES];
dispatch_async(dispatch_get_global_queue(0,0), ^{
self.imageButtonURL = #"http://bundoransurfshop.com/wp-content/uploads/2015/02/72-torq-pink.jpg";
imageButtonData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:self.imageButtonURL]];
if ( imageButtonData == nil )
return;
dispatch_async(dispatch_get_main_queue(), ^{
self.imageButton.imageView.image = [UIImage imageWithData: imageButtonData];
});
});
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"modifyShop"]) {
ShopModify *viewcontroller = (ShopModify *)segue.destinationViewController;
viewcontroller.imageButtonURL = self.imageButtonURL; }
}
-(IBAction)prepareForUnwind:(UIStoryboardSegue *)segue {
NSLog(#"%#", self.imageButtonURL);}
ModifyShop:
- (void)viewDidLoad {
[super viewDidLoad];
}
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.photoURL.text = [NSString stringWithFormat:#"%#", self.imageButtonURL];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
Shop *viewcontroller = (Shop *)segue.destinationViewController;
viewcontroller.imageButtonURL = self.photoURL.text;
}
That makes my app crashes :
[Reports setImageButtonURL:]: unrecognized selector sent to instance
The error is saying that you are tying to set imageButtonURL on an instance of Reports, not on Shop which is what you think your destination view controller is. It appears that your unwind is going to the wrong controller. You must have hooked up the unwind segue incorrectly. You say that you have 2 views (view controllers actually), but you must also have a Reports class in your app.
I have a segue that is being called progmatically by performSegueWithIdentifier: but it will not trigger. However, when I create the segue with a button press the segue works without a problem. I have also tried changing the name of my segue in code, and it produces a no segue with identifier error.
Here is my code (Note: the segue is called in two different places to check if it would work somewhere else in the code.)
#import "SignUpViewController.h"
#import "ProgressHUD.h"
#interface SignUpViewController ()
#end
#implementation SignUpViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
[self performSegueWithIdentifier:#"profilePic" sender:self];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
- (IBAction)createAnAccount:(id)sender {
[ProgressHUD show:#"Please Wait"];
if ([self.passwrod.text isEqualToString:self.confirmPassword.text]){
// Register User
PFUser *user = [PFUser user];
user.username = self.username.text;
user.password = self.passwrod.text;
user.email = self.eMail.text;
// other fields can be set if you want to save more information
NSString *name = [self.firstName.text stringByAppendingString:#" "];
NSString *fullName = [name stringByAppendingString:self.lastName.text];
user[#"name"] = fullName;
user[#"posts"] = #0;
user[#"score"] = #5;
user[#"followers"] = #0;
user[#"following"] = #0;
[user signUpInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
if (!error) {
// Hooray! Let them use the app now.
[self performSegueWithIdentifier:#"profilePic" sender:self];
[ProgressHUD showSuccess:nil];
NSLog(#"Perform Segue");
} else {
NSString *errorString = [error userInfo][#"error"];
// Show the errorString somewhere and let the user try again.
[ProgressHUD showError:errorString];
}
}];
} else {
// Alert User
[ProgressHUD showError:#"Please check your passwords as they do not match."];
}
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSLog(#"Preparing for segue");
NSLog(#"Segue: %#", segue.identifier);
}
#end
Update for clarification: The prepareForSegue method is being called and logging.
Thanks for your help!
You shouldn't call performSegueWithIdentifier in viewDidLoad. In fact, I'm pretty sure you'll see a warning or error in the console if you do. Move the call to viewDidAppear instead.
The solution that worked for me was to delete all the segues to the view controller in question and then re-added them. This porbably won't work for everyone, but it is worth a shot.
I am trying to pick an image from the photo library and perform a segue only if the user selects an image. (Does nothing if the user presses cancel)
Is it possible to pack all of this action into one single button press via IBAction?
The issue I am facing with my attempted code is that it tries to perform the push segue right when I press the button, which apparently is at the same time I am trying to access the photo library. I can't figure out how to get the image picker to go first and then have the push segue trigger immediately after, depending on whether an image was picked or the process was canceled.
ViewController.m
- (IBAction)LibraryButton:(id)sender
{
imagePicker.delegate = self;
imagePicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:imagePicker animated:YES completion:nil];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:#"takeLibraryPhoto"])
{
buffer = modBuffer;
selectDisplayViewController *secondVC = [segue destinationViewController];
}
else if ([segue.identifier isEqualToString:#"takeCameraPhoto"])
{
}
else if ([segue.identifier isEqualToString:#"takeCameraVideo"])
{
}
}
- (BOOL) shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
if([identifier isEqualToString:#"takeLibraryPhoto"])
{
//[self presentViewController:imagePicker animated:YES completion:nil];
if(modBuffer != NULL)
{
return true;
}
return false;
}
else
{
return true;
}
return false;
}
- (void) imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
/*UIImage *loadImage;
loadImage = [info valueForKey:UIImagePickerControllerOriginalImage];
buffer = loadImage;*/
modBuffer = [info valueForKey:UIImagePickerControllerOriginalImage];
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void) imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidLoad
{
imagePicker = [[UIImagePickerController alloc]init];
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
selectDisplayViewController.m
#implementation selectDisplayViewController
#synthesize selectDisplayView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
selectDisplayView.image = buffer;
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
What my code currently does is... When I load an image, "buffer" of selectDisplayViewController is successfully getting data from "modBuffer", but by then the push segue has already occurred and it returns me to the original view controller that I press the button from. It isn't until I press the button a second time (could also press cancel this time) that it takes me to the other view controller where it displays my image.
I have been struggling with this for many days now. How can I get this to behave more like a sequence where its a step process instead of the push segue happening right away!! :(
All help is greatly appreciated. Thanks :)
Not really sure I completely follow but it sounds like you want to perform the segue after the user selects a picture or presses cancel from the image picker.
If that's the case then you can do that in the delegate methods using [self performSegueWithIdentifier:#"foo" sender:nil];
I tried to implement stripe into an iOS app through its online documentation. Everything good so far, now pushing the paymentView onto my navigation controller stack I get a completely broken screen. Thought it'd be a problem with the stripe view but when I do not log in (see code below - no identification token given) and the login screen is being pushed instead, it is completely black too. It cant be a problem with that view cause it loads just fine if I push the login view from another view before this one.
So why does pushing view via the buyButtonAction below give me black / fucked up screens?!
Ive been on this for hours.. nothing seems to work.
A pic:
the important code part:
#interface PaymentViewController ()
#end
#implementation PaymentViewController
#synthesize stripeCard = _stripeCard;
#synthesize stripeView;
#synthesize passedProductId;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
self.stripeView = [[STPView alloc] initWithFrame:CGRectMake(15,20,290,55)
andKey:#"pk_test_45mqixOu8N9S4lQ6cdn1OXBD"];
self.stripeView.delegate = self;
[self.view addSubview:self.stripeView];
}
And the call:
-(void)buyButtonAction:(id)sender
{
tokenClass *tokenObject = [tokenClass getInstance];
NSLog(#"%#", tokenObject.token);
if (tokenObject.token == nil) {
LoginController *loginController = [[LoginController alloc] init];
[self.navigationController pushViewController:loginController animated:YES];
} else {
NSLog(#"%#", tokenObject.token);
CGPoint hitPoint = [sender convertPoint:CGPointZero toView:self.tableView];
NSIndexPath *hitIndex = [self.tableView indexPathForRowAtPoint:hitPoint];
PaymentViewController *payView = [[PaymentViewController alloc] init];
payView.passedProductId = [[self.productData valueForKey:#"id"] objectAtIndex:hitIndex.row];
NSLog(#"passing %#", payView.passedProductId);
// push payment view
payView.navigationItem.title = #"One-Click-Payment";
[self.navigationController pushViewController:payView animated:YES];
}
}
We can see that there's a view behind the navigation bar. It's an iOS 7 related issue. Add this line to your viewDidLoad:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
Or change your self.stripeView frame by adding 64 to y:
CGRectMake(15,84,290,55)
Useful link: https://stackoverflow.com/a/18103727/1835155