I have a tableview with UITextFields to build a form. I then have a button in the toolbar which launches a modal view controller to select some data which is then passed back to the tableview. However, the new data that was selected does not get refreshed into the UITextField using textField.text = valueReturnedFromModal syntax. Is there something I'm missing?
I see that the data is being returned properly from the modal so that is not the issue. I'm just having trouble forcing the UITextField to refresh with the new data. I've tried forcing a reloadData on the tableview as well.
So from the modal view, here's the code that passes data back:
- (void)doneAccountSelection:(id)sender
{
[delegate didSelectAccount:currentAccount];
[self dismissModalViewControllerAnimated:YES];
}
and here's the actual method in the delegate:
- (void)didSelectAccount:(SFAccount *)selectedAccount
{
//Ensure a valid deal exists for the account to be attached to
[self createDealObjectIfNeeded];
//Set the deal account
[self.deal setAccount:selectedAccount];
//Refresh the text fields
//Tag 3: Account Name field
UITextField *acct_name = (UITextField *) [self.view viewWithTag:3];
[acct_name setText:self.deal.account.field_acct_name_value];
//Tag 4: Account City field
UITextField *acct_city = (UITextField *) [self.view viewWithTag:4];
[acct_city setText:self.deal.account.field_acct_city_value];
//Save the context changes. A new deal gets created above if one does not exist.
if ([self saveModel]) NSLog(#"Acct object created, attached to deal successfully!");
[self.tableView reloadData];
}
Would you mind posting the code that sets the text fields data and the code that passes the data back to the table view?
Answer:
It appears that you are properly setting the data, however, you are dismissing the modal view controller after sending the delegate message. In this scenario, the table view is not even created until after the dismissModalViewControllerAnimated: has ended. Which means the textfields are NULL until the view is present. What I suggest is call
[self dismissModalViewControllerAnimated:YES];
as the first line in the didSelectAccount: delegate method. This would dismiss the modal view and then continue on with your setting the data to valid textfields as -viewWillAppear: / -viewDidAppear: would have already been called. Everything seems ok it's just the order that may be tripping you up. Although
-dismissModalViewControllerAnimated:
is passed to its parent if a view controller does not have a modal view (because it is the modal view), it seems more appropriate to call this method in the delegate method where you will eventually manipulate the view due to new data, etc.
use this after getting Value in text field:
[self.tableView ReloadData];
After some serious debugging found that self.account was being used in cellForRowAtIndexPath to set the initial UITextField values within the UITableViewCell. Then after modal selection completed, I was only updating the account reference for the deal object and not updating the self.account object.
I then added to this by creating a new method called updateTextFieldsAfterModalFinished and moved the code to update the UITextFields there. This method was then called from didSelectAccount which is the delegate method for modal view that is dismissed. Things are now working as expected and the UITextFields get updated after modal selection is finished.
Related
I’m I downloaded MZFormSheetController library for my app.
I’ve got a problem on my popup. When I am on my TableViewController, I tap on a row to get popup to open up so that I can change the name. The popup opens, I set the name and when I tap on the button to correct the name, I call the button method but i can’t close my popup while reload my list.
- (IBAction)modifierTournoi:(id)sender {
//code to update database
//this method close the popup but don't call method viewWillAppear to reload database
//I don't know what method i can use..?
[self dismissFormSheetControllerAnimated:YES completionHandler:^(MZFormSheetController *formSheetController) {
}];
}
Before that, I used the method popViewControllerAnimated to come back to my list while recharging my list.
- (IBAction)modifierJoueur:(id)sender {
//code to update database
[self.navigationController popViewControllerAnimated:true];
}
Can you help me please ?
Thank you very much.
It looks like there is a specific completion handler for this purpose built into the library you are using:
- (IBAction)modifierTournoi:(id)sender {
//code to update database
//this method close the popup but don't call method viewWillAppear to reload database
//I don't know what method i can use..?
[self dismissFormSheetControllerAnimated:YES completionHandler:^(MZFormSheetController *formSheetController) {
// Reloading your database should work in here.
}];
}
The reason viewWillAppear will not be being called is because rather than placing a viewController modally above your window, I imagine MZFormSheetController will be adding a UIView above all presented UIViews, so viewWillAppear will never be called. But as I said above, you should be able to reload in the completion handler block.
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 8 years ago.
I have two view controllers.
First one is Custom view controller that loads the images from asset library.
Second view controller shows the full size of selected image with cancel & Delete button
I have used the below code for delete the selected image from custom view controller.
customviewcontroller.m
-(void)deleteItemsFromDataSourceAtIndexPaths:(NSArray *)itemPaths
{
//here i want to control the delete option when cancel pressed
NSMutableIndexSet *indexSet = [NSMutableIndexSet indexSet];
for (NSIndexPath *itemPath in itemPaths) {
[indexSet addIndex:itemPath.row];
}
[self.selectedAssets removeObjectsAtIndexes:indexSet];
}
/* call the delete function*/
- (void) collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
NSArray *selectedItemsIndexPaths = [self.collectionview1 indexPathsForSelectedItems];
[self deleteItemsFromDataSourceAtIndexPaths:selectedItemsIndexPaths];
[self.collectionview1 deleteItemsAtIndexPaths:selectedItemsIndexPaths];
}
This working fine for delete the selected image from custom view controller.
but It works also cancel. Now, I want to control deletion on cancel.
kindly help me to solve this.
I have already tried using button tag for identify which button was pressed. but can't control in custom vc
secondview.m
- (IBAction)CancelPhoto:(id)sender{
[Cancel setTag:1]; //set tag value at cancel
}
There are several ways to pass date between view controllers. I'm giving you a very simple solution as per your requirements:
Assuming you have all your images in a mutable array in first view controller.
NSMutableAray *imagesArray;
Make a property images array of NSMutableArray type in second view controller.
#property(nonatomic, strong) NSMutableAray *imagesArray;
assign your array to property while pushing/presenting view
secondController.imagesArray = imagesArray;
On delete event remove that image from array.
[self.imagesArray removeObjectAtIndex:selectedIndex];
dismiss/pop your second view where ever you want and refresh your first view controller in viewWillAppear of viewDidAppear method.
As you have passed reference of your main images array, both classes (view controllers) share same array through pointer and a change in array from either side will be reflected in both screens
There are 3 ways (in my opinion):
Delegate
Notification
In case: you are using database, just remove image url and reload data
It's this case again:
I wish to fill the prototype cells with the names of the friends selected in the UIPickerView over there. I have programatically filled the picker with the string representation of my Player object data, and set its properties using the delegate functions.
The "New Game Friends View" you see here has its own viewcontroller subclass, as has the table view, which I attempt to embed into a UIView on the "New Game Friends View". The table view IS an instance of my WHGFriendTableViewController class. I know this because this function does not throw any exceptions:
- (IBAction)addBtnClicked:(id)sender {
WHGFriendTableViewController* tabView = (WHGFriendTableViewController*) [[self childViewControllers] objectAtIndex:0];
NSInteger row = [friendPicker selectedRowInComponent:0];
[[tabView selectedFriends] addObject:[[self friendList] objectAtIndex:row]];
[[tabView tableView] reloadData];
}
Now the problem is: while the function above does not throw any exceptions, it still does not work. It appears that nothing really happens when I insert the objectAtIndex:row into the NSMutableArray selectedFriends (which is a property) in the table view's view controller.
This:
NSLog(#"New length: %d", [[tabView selectedFriends] count]);
prints 0 after inserting the new object. I have no idea why. Printing the count of [self friendList] gives three, just as I expect. The reloadData message does not make anything appear in the table view.
Any ideas why I cannot insert new data into the table view with my code, when this seems to be working with no exceptions whatsoever? Thanks in advance!
Have you alloced & init your NSMutableArray selectedFriends?
Also have you set the dataSource and delegate of your table view?
I have a uiswitch view in a static table. I am trying to retrieve it via its tag in the viewdid load method. For some reason it always shows null. I do it with the viewWithTagMethod.
UISwitch* switch = (UISwitch*)[self.view viewWithTag:tag];
[switch setOn:[value boolValue] animated:YES];
Static table view contents are not loaded until after the super implementation of viewWillAppear:animated: has been called. Move your code to a later point and you should be fine. Alternatively, just use an outlet.
I am working on an iOS app that uses a very common Core Data based tableview to display items and when one it selected, it shows a more detailed view, much like the Contacts app. The detail view itself is a programmatically generated grouped table with a custom (nib-defined) view for a header that has a picture and a name. Some of the cells in the table are custom cells that have a label name and a textbox value. In "edit" mode, the editable table cells (and the name in the header) have .clearButtonMode set to UITextFieldViewModeAlways to show that they are editable.
I am currently using the same view controller to display the detailed information, edit the information, and add a new record to the original list.
When a new item is being added, the view controller is created modally with a custom init overload that sets a flag in the view controller to indicate that it is adding the record. This allows it to start in edit mode and if edit mode is left, the model view is dropped away. The right menubar button is the usual Edit/Done, and the left one is a cancel button. When an existing item is being edited, the left button (normal back button) is replaced with a cancel button.
I am starting to have second thoughts as to whether or not having one view controller handle three different modes is the way to go. There are few issues that I am not sure how to handle.
1) How do I tell if edit mode is left by hitting "Done"? Is there an action for it? If cancel is hit, the action either dismisses itself (add mode) or restores the previous values leaves edit mode. I suppose I could put a check in my setEditing override to handle it, but it seems that there should be a better way.
2) When edit mode is entered and I set the editable text fields to UITextFieldViewModeAlways, is there a way to animate the appearance of the 'X' buttons so that they fade in with the editing indicators on the regular cells?
Are there easy solutions to these problems or is my 3-in-1 view controller a bad idea? It doesn't seem right to remake the same view for different modes, but having multiple modes for a view controller seems to be a bit of a hassle.
jorj
I like the 3-in-1 approach and use it all the time. There are lots of advantages: one xib, one view controller, one simple protocol between the list and detail view controllers. Yes, there are a few more checks like if (self.editing) ... but I like that better than more view controllers and xibs.
To help with adding I expose a BOOL that the delegate can set.
#property (nonatomic) BOOL adding;
1) The built-in editButtonItem does not allow you to intercept it before setEditing:animated: This is problematic when you are doing data validation after Done is tapped. For that reason I rarely use editButtonItem and use my own Edit, Done, and Cancel buttons with their own action methods. See below.
2) For this I like UITableView's reloadSections:withRowAnimation. It might work in your case.
- (void)edit:(id)sender
{
self.editing = YES;
}
- (void)done:(id)sender
{
// data validation here
if (everythingChecksOut)
{
//save here
} else {
return; //something didn't validate
}
//if control reaches here all is good
//let the delegate know what happened...
if (self.adding) {
[self.delegate didFinishAddingWithData:self.yourData];
} else {
[self.delegate didFinishEditingWithData:self.yourData];
}
self.adding = NO;
self.editing = NO;
}
- (void)cancel:(id)sender
{
[self.view endEditing:YES]; //in theory, forces the view that is editing to resign first responder
//in practise I find it doesn't work with the YES parameter and I have to use my own flag
// roll back any changes here
self.editing = NO;
if (self.adding) //let the delegate know we cancelled the add...
{
[self.delegate didCancelAdd];
}
}
- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{
[super setEditing:editing animated:animated];
//set your nav bar title
[self.tableview.editing = editing]; //you may or may not require this
[self.tableview reloadSections... withRowAnimation:yourChoice];
if (editing)
{
//install your Done and Cancel buttons
} else {
//remove Cancel and put the Edit button back
}
}
Then in viewDidLoad...
- (void)viewDidLoad
{
[super viewDidLoad];
//whatever else you do
if (self.adding)
{
self.editing = YES;
}
}
I haven't fully understood the questions you have raised, but here are some thoughts on structure which are probably more useful in the first instance...
It seems you are doing too much with a single UITableViewController and inevitably you will end up with lots of if statements and confusing code. I'd break it down into two separate UITableViewControllers, one to handle the main view (and any subsequent editing mode you require) and then another to handle the detail view. Either or both of these could then use nibs as you require.
Using two controllers like this will allow you to simply push the second detailViewController onto a navigation stack, rather than presenting it modally which doesn't seem like the obvious thing to do in this instance.
However, if you would prefer it to be presented modally, you could write a protocol for the detailView which sends messages in the event of 'Cancel', 'Edit' or 'Done' buttons being pushed. The first viewController could then implement the protocol and receive these events.
I hope that helps...