hi i am working on an app and all was going good till now.... i am stuck at this point..
here is my storyboard snapshot..
in the DemoTableViewController when i clock on "filters" button .. Brands TableViewController is opened modally .
after user select multiple rows in Brands TableViewController ,, he then clicks on done button and view controller is dismissed by this code:
-(IBAction)DonePressed:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
}
I am storing the user selections in NSMutableSet and it is to be Used in DemoTableViewController so that i can reload the table rows according to the selection but i dont know how to send NSMutableSet to DemoTableViewController and then reload the table according to selection..
what is the right way to dismiss modal view and reload the parent DemoTableViewController
i know i am not doing it correctly but can anyone help me in doing it...
here is some code ---
DemoTVC.h
#import <UIKit/UIKit.h>
#import "MyModelClass.h"
#import "brandsTableViewController.h"
#interface demoTableViewController : UITableViewController<UITableViewDataSource,UITableViewDelegate,MyModelProtocol,FilterProtocol>
#property (strong, nonatomic) IBOutlet UITableView *demoTable;
- (IBAction)FilterPressed:(id)sender;
#end
DemoTVC.m--
the method which performs segue--
- (IBAction)FilterPressed:(id)sender {
[self performSegueWithIdentifier:#"FilterPressed" sender:self];
}
the delegate method which is called to get the values from BrandsTVC--
-(void)GetTheSet:(NSMutableSet *)MySet{
[self dismissViewControllerAnimated:YES completion:nil];
}
viewdidLoad--
- (void)viewDidLoad
{
[super viewDidLoad];
productArray = [[NSMutableArray alloc] init];
homeModel = [[MyModelClass alloc] init];
// Set this view controller object as the delegate for the home model object
homeModel.delegate = self;
// Call the download items method of the home model object
[homeModel downloadItemswithurl:#"url is written here"];
}
BrandsTVC.h---
#import <UIKit/UIKit.h>
#import "MyModelClass.h"
#protocol FilterProtocol <NSObject>
-(void)GetTheSet:(NSMutableSet *) MySet;
#end
#interface brandsTableViewController : UITableViewController<UITableViewDataSource,UITableViewDelegate,MyModelProtocol>
#property (strong, nonatomic) IBOutlet UITableView *RetailerList;
#property (strong,nonatomic) NSMutableSet *selectStates;
#property (nonatomic, weak) id<FilterProtocol> delegate;
- (IBAction) DonePressed:(id)sender;
#end
BrandsTVC.m---
#interface brandsTableViewController ()
{
MyModelClass *myModelClass;
NSMutableArray *BrandsArray;
brandsTableViewController *Delegate;
}
#end
viewDidLoad----
- (void)viewDidLoad
{
[super viewDidLoad];
BrandsArray = [[NSMutableArray alloc] init];
self.selectStates=[NSMutableSet new];
myModelClass = [[MyModelClass alloc] init];
// Set this view controller object as the delegate for the home model object
myModelClass.delegate = self;
// Call the download items method of the home model object
[myModelClass downloadItemswithurl:#"url to get json"];
self.tableView.allowsMultipleSelection = YES;
}
Done Button is called ---
- (IBAction)DonePressed:(id)sender {
[self dismissViewControllerAnimated:YES completion:nil];
id<FilterProtocol> strongDelegate = self.delegate;
if ([strongDelegate respondsToSelector:#selector(GetTheSet:)]) {
[strongDelegate GetTheSet:self.selectStates];
}
}
#end
You can keep those elements in NSUserDefaults, and whenever DemoTableViewController appears, you send [tableView reloadData]. Do this in the viewDidAppear: method.
You can also use Core Data, but there are a lot of details to explain how to do that.
After a lot of trial and error i come to know that in BrandsTVC--
- (IBAction)DonePressed:(id)sender {
NSLog(#"done pressed %#",self.delegate);
[delegate GetTheSet:self.selectStates];
}
self.delegate is giving me NULL.
delegate is not setup and i cant figure out how to do that.. someone help me..
this answer solved my problem :D
custom viewcontroller delegate not working
Related
Through delegation I created a view controller that takes the input from textfields and passes it back and adds it to an nsmutablearray, successfully adding a row for it. whenever i navigate away from the tableview my newly appended object just disappears. Here is some code to give you a better idea of what i might be doing wrong.
TableViewController.h -
#interface TableViewController : UITableViewController<UITableViewDelegate, UITableViewDataSource>
#property(strong,nonatomic)NSMutableArray *codeList;
#property(strong,nonatomic)NSMutableArray *codeArray;
#end
TableViewController.m -
#interface TableViewController ()
#end
#implementation MCTableViewController
#synthesize codeList;
#synthesize codeArray;
- (void)viewDidLoad {
[super viewDidLoad];
self.tableView.delegate = self;
self.tableView.dataSource = self;
self.codeList = [NSMutableArray arrayWithObjects:#"Array",
#"Pointer",
#"Class",
#"Protocol",
#"Delegate",
nil];
self.codeDescArray = [NSMutableArray arrayWithObjects:
#"Array Description",
#"Pointer Description",
#"Class Description",
#"Protocol Description",
#"Delegate Description",
nil];
)
In the same class I programmatically created a button that moves to the view where data is supposed to be passed back. code below. This is done through delegation.
- (void)addNewCodeButtonPressed {
AddNewCodeVC *addVC = [[AddNewCodeVC alloc] init];
addVC.dataDelegate = self;
UINavigationController *navBar = [[UINavigationController alloc]initWithRootViewController:addVC];
[self.navigationController presentViewController:navBar animated:YES completion:nil];
}
Here is where the delegate logic is created in AddNewCodeVC.h -
#import <UIKit/UIKit.h>
#import "TableViewController.h"
#class AddNewCodeVC;
#protocol addNewCellData <NSObject>
- (void)sendDataToTableView:(NSString*)code codeDesc: (NSString*)desc;
#end
#interface AddNewCodeVC : UIViewController<UITextFieldDelegate> {
__weak id dataDelegate;
}
#property(weak,nonatomic)id<addNewCellData>dataDelegate;
#property(strong,nonatomic)UITextField *codeTextfield;
#property(strong,nonatomic)UITextField *descTextfield;
#end
finally here is the AddNewCodeVC.m -
#import "AddNewCodeVC.h"
#interface AddNewCodeVC ()
#end
#implementation AddNewCodeVC
#synthesize dataDelegate;
- (void)viewDidLoad {
[super viewDidLoad];
self.codeTextfield.delegate = self;
self.descTextfield.delegate = self;
//Programmatically created both textfields, nothing special
}
//"saveNewCode" is action for another button i created
- (void)saveNewCode {
sendDataToTableView:self.codeTextfield.text codeDesc:self.descTextfield.text];
[self.dataDelegate sendDataToTableView:self.codeTextfield.text codeDesc:self.descTextfield.text];
NSLog(#"CODE: %#", self.codeTextfield.text);
NSLog(#"DESC: %#", self.descTextfield.text);
[self dismissViewControllerAnimated:YES completion:nil];
}
The code works but nsmutable array wont hold the passed values if i navigate away from the TableViewController. I think this is because my main view controller programmatically segues to the tableview controller and creates a new instance of it, so that might have some effect? I'll leave some code below just in case it is relevant.
MainviewController.m -
- (void) tableViewBtnPressed:(UIBarButtonItem *)sender {
TableViewController *tableVC = [[TableViewController alloc] init];
//This for another delegate I created, not relevant
tableVC.selectedDataDelegate = self;
UINavigationController *navBar = [[UINavigationController alloc]initWithRootViewController:tableVC];
[self.navigationController presentViewController:navBar animated:YES completion:nil];
}
Hopefully this code is enough to illustrate the problem, i hope someone has an idea whats going on with the NSMutableArray, and why it isn't holding any new objects that are passed into it, any help is appreciated.
i have 2 views in iPhone application. FirstViewController and MultiSelectViewController.
in FirstViewController there is a button to go to MultiSelectViewController. In MultiSelectViewController i have a tableviewcontroller to multiselect and send result back to FirstViewController with Done button
my problem is with done button. i don't know how to send data back to the FirstViewController. it has to be with dissmissviewcontroller.
this is .h file of MultiSelectViewController
#protocol MultiSelectDelegate <NSObject>
-(void) multiselectViewControllerDismissed;
#end
#interface MultiSelectViewController : UITableViewController
{
__weak id myDelegate;
}
#property(nonatomic,retain)NSArray *myData;
#property(nonatomic, retain)NSMutableArray *selectedData;
#property (nonatomic, weak) id<MultiSelectDelegate> myDelegate;
this is my done button in .m file of MultiSelectViewController
- (void)viewDidLoad
{
[super viewDidLoad];
self.tableView.allowsMultipleSelection = YES;
selectedData=[[NSMutableArray alloc] init];
UIBarButtonItem *barButton = [[UIBarButtonItem alloc] initWithTitle:#"Done"
style:UIBarButtonItemStyleBordered
target:self
action:#selector(multiselectViewControllerDismissed)];
self.navigationItem.rightBarButtonItem = barButton;
}
and lastly here is my done button action:
-(void)multiselectViewControllerDismissed
{
NSLog(#"%#",selectedData);
}
i don't understand how can i send data and get back in FirstViewController
You redefine
multiselectViewControllerDismissed delegate method as
multiselectViewControllerDismissedWithData:(NSMutableArray *)dataSelected
And, in .h file of FirstViewController implement the delegate i.e.,
#interface FirstViewController: UIViewController <MultiSelectDelegate>
and in the button action of FirstViewController.m assign delegate of MultipleSelectViewController as self. ie.,
MultipleSelectViewController * msvc = [[MultipleSelectViewController alloc] init];
msvc.myDelegate = self;
and implement
-(void)multiselectViewControllerDismissedWithData:(NSMutableArray *)dataSelected
this method in FirstViewController.m
And, in the Done button action method of MultipleSelectViewController.m, call method multiselectViewControllerDismissedWithData with delegate i.e.,
[self.myDelegate multiselectViewControllerDismissedWithData:selectedData];
That's it.
You could now pass selectedData array from MultipleSelectViewController to FirstViewController
Two standard ways of passing data in obj-c:
Use references and assign manually. In your example, the first view controller passes a reference of itself to the second view controller. The second view controller assigns a designated property with the required data using the reference.
The publisher-subscriber pattern using LocalNotifications. The first view controller listens for a particular location notification, and the second view controller, before being dismissed, does a broadcast with the data.
I'd recommend the 1st approach for your example. Some sample code:
In the .h file:
#interface FirstViewController:UIViewController
#property NSMutableArray *receivedData; //property to receive selected data
#end
In the .m file:
MultiSelectViewController *msvc = [MultiSelectViewController alloc] init];
msvc.presentingViewController = self; // pass reference of 1st VC to 2nd VC
[self presentViewController:msvc animated:YES];
In MultiSelectViewController.h file:
#import "FirstViewController.h"
#interface MultiSelectViewController: UITableViewController
...
#property FirstViewController *presentingViewController;
...
#end
In MultiSelectViewController.m file:
-(void)multiselectViewControllerDismissed
{
NSLog(#"%#",selectedData);
presentingViewController.receivedData = selectedData;
}
first create your delegate method as
-(void)dismiss:(NSString *)str;
while did select get a value from based on indexpath.row
and store it as nsstring.
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
self.valueString=[NSString stringWithFormat:#"%#",[self.arrayValue objectAtIndex:indexPath.row]];
NSLog(#"%d",indexPath.row);
}
done button click:
call your delegate method like
[self. myDelegate dismiss:"your string which you get from table"]
[[self navigationController] popViewControllerAnimated:YES];
and in your first view controller…
import the view controller class and call delegate method..
create instance for second view controller...
MultiSelectViewController *txtNext=[[MultiSelectViewController alloc]init];
txtNext. myDelegate =self;
then
-(void)dismiss:(NSString *)str
{
NSString *strng=str;
nslog("%#",strng);
}
I am trying to use a delegate method in AddCity.m controller that I created in the City.m controller. The method is
City.m
- (void)EditCityController:(id)controller didEditItem:(id)item
{
if(item)
{
NSDictionary *d = (NSDictionary *)item;
[self.model addNewCity:[d valueForKey:#"cityName"] forProvince:self.ro inMayor:[d valueForKey:#"mayorName"] inPopulation:[[d valueForKey:#"population"]intValue] inYearEstablished:[[d valueForKey:#"yearEstablished"]intValue]];
[self.model saveChanges];
}
// Dismiss the modal view controller
[controller dismissViewControllerAnimated:YES completion:nil];
}
City.h
#interface Cities :
UITableViewController<NSFetchedResultsControllerDelegate, EditCityDelegate>
And then in AddCity.h i have
#protocol EditCityDelegate;
#interface AddCity : UIViewController<UITextFieldDelegate>
#property (nonatomic, assign) id <EditCityDelegate> delegate;
#protocol EditCityDelegate <NSObject>
- (void) EditCityController:(id)controller didEditItem:(id)item;
#end
I am calling it from AddCity.m (Currently trying to the cancel button).
- (IBAction)cancel:(id)sender {
[self.delegate EditCityController:self didEditItem:nil];
}
When i put a breakpoint what happens is that it hits the self.delegate line but it does not go into the EditCityController method in the City.m controller.Any idea on what i am doing wrong?
I assume you call AddCity.m in City.m and present it using presentViewController
AddCity *addcityVC = [AddCity new];
addcityVC.delegate = self; // initialize the delegate here
[self presentViewController:addCityVC animated:YES completion:nil];
You need to initialize the delegate back to self so it can call the method you need
Hope this helps
I have been searching all morning how to do this. I have 2 View Controllers. From the root View Controller (ViewControllerA - which is a table view controller) you can go push to the second view controller (ViewControllerB).
In the ViewControllerB, there are two fields: contacts & textBody. When the user is done they can click on "Add". This will then go back to ViewControllerA. What I am trying to do now, is for every time that process occurs, all the information from ViewControllerB the user just added goes into a cell in ViewControllerA. The user can then add as many cells as they like.
What I can't do however, is get the information across the view controllers. I have been looking all morning at using the app delegate, singletons??, protocols, sharing properties, etc! But I am still stuck.
What I want to do, but can't, is for every time the user clicks "Add" on ViewControllerB, contacts & texts are put into an array. This array is then put into another array which holds all the smaller arrays which the user has created? If you have an ideas, or links to similar/sample code or tutorials, that would be much appreciated!
Try this using the delegate method as follows
Download Sample Project with XIBs
Download Sample Project With Storyboard
ParentViewController.h
#import <UIKit/UIKit.h>
#interface ParentViewController : UIViewController {
NSMutableArray *dataArray;
}
- (void)passData:(NSMutableArray *)array;
#end
ParentViewController.m
#import "ParentViewController.h"
#import "ChildViewController.h"
#implementation ParentViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Initialise the mutable array.
dataArray = [[NSMutableArray alloc] init];
}
- (IBAction)btnGoToSecondView:(id)sender {
ChildViewController *secondVC = [[ChildViewController alloc] initWithNibName:#"ChildViewController" bundle:nil];
secondVC.delegate = self;
[self presentViewController:secondVC animated:YES completion:nil];
}
- (void)passData:(NSMutableArray *)array {
[dataArray addObject:array];
NSLog(#"Data Passed = %#",dataArray);
}
#end
ChildViewController.h
#import <UIKit/UIKit.h>
#import "ParentViewController.h"
#class ParentViewController;
#interface ChildViewController : UIViewController {
NSMutableArray *tempArray;
}
#property (strong, nonatomic) IBOutlet UITextField *txtContact;
#property (strong, nonatomic) IBOutlet UITextField *txtTextBody;
#property(nonatomic, assign) ParentViewController *delegate;
#end
ChildViewController.m
#implementation ChildViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Initialise the mutable array.
tempArray = [[NSMutableArray alloc] init];
}
- (IBAction)btnPassDataBack:(id)sender {
if([self.delegate respondsToSelector:#selector(passData:)]) {
[tempArray addObject:_txtContact.text];
[tempArray addObject:_txtTextBody.text];
[self.delegate passData:tempArray];
}
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)viewDidUnload {
[self setTxtContact:nil];
[self setTxtTextBody:nil];
[super viewDidUnload];
}
#end
With Storyboard
If you are using storyboard then create a ParentViewController segue ChildViewController and give it a identifier in my sample it showChildView
Then use the following code to set the delegate
// Calling the segue to go to the child view and setting up the delegate.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showChildView"]) {
ChildViewController *childVC = segue.destinationViewController;
childVC.delegate = self;
}
}
Then to dismiss back to the ParentViewController use the following code (from my sample)
- (IBAction)btnPassDataBack:(id)sender {
if([self.delegate respondsToSelector:#selector(passData:)]) {
[tempArray addObject:_txtContact.text];
[tempArray addObject:_txtTextBody.text];
[self.delegate passData:tempArray];
}
[self.navigationController popToRootViewControllerAnimated:YES];
}
I would recommend using a singleton instance of your NSMutableDictionary as they have bailed me out of your exact situation multiple times (including custom frameworks and UITabBarControllers). Here is an example I'm currently using to implement a singleton. This methodology is also ARC-safe as well
mySingleton.h
#import <Foundation/Foundation.h>
#interface mySingleton : NSObject {
}
+ (NSMutableDictionary *) myMutableDict;
#end
mySingleton.m
#import "mySingleton.h"
#implementation mySingleton
+ (NSMutableDictionary *)myMutableDict
{
static NSMutableDictionary *singletonInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
singletonInstance = [[NSMutableDictionary alloc]init];
});
return singletonInstance;
}
#end
As long as you include mySingleton.h in all of your view controllers you can access the data via [mySingleton myMutableDict]. For example: [[mySingleton myMutableDict] setObject:myObject forKey:myKey];
Good luck!
If the information is really "global" - it has only one instance across the whole app - then you should create a singleton as DB80Buckeye suggested.
If the information is something that truly belongs to ViewController1 and you want it to be modified in ViewController2 (ie ViewController2 is really part of ViewController1, it just happens to be on another screen), then you should pass that as part of the constructor of ViewController2.
-(void)view_controller_1_that_push_view_controller_2_onto_the_stack {
ViewController2* vc2 = [[ViewController2 alloc] initWithInformation:your_information];
[self.navigationController pushViewController:vc2 animated:YES];
}
#interface ViewController2
-(id)initWithInformation:(YourInformationClass*)info;
#end
Another way is to use notifications.
There are two ways to go here. The standard pattern for doing this is delegation. You don't need a singleton. ViewControllerA manages and lists your data. ViewControllerB doesn't need to know anything about all of that data so there's no reason to expose it via a singleton, etc.
Create a delegate protocol in ViewControllerB's header file. Something like this:
#protocol ViewControllerBDelegate
- (void)addContact:(NSString *)contact withBody:(NSString *)textBody;
#end
Now, specify that ViewControllerA will implement the delegate protocol in its header:
#interface ViewControllerA : UIViewController <ViewControllerBDelegate>
Don't forget to import ViewControllerB.h at the top of ViewControllerA's header.
In ViewControllerA's implementation, implement the delegate method you specified in the protocol:
- (void)addContact:(NSString *)contact withBody:(NSString *)textBody {
[self.someArray addObject:[[SomeObject alloc] initWithContact:contact body:textBody]];
[self.tableView reloadData];
}
That's obviously just an example -- not sure how you're managing your data structure and it's probably better to insert the cell someplace that makes sense.
Declare a delegate reference in ViewControllerB's header:
#property (weak, nonatomic) id<ViewControllerBDelegate> delegate;
When you present ViewControllerB, set ViewControllerA as the delegate.
ViewControllerB *b = [[ViewControllerB alloc] init...];
b.delegate = self;
In the selector triggered by the add button in ViewControllerB, call back on the delegate before popping the view controller off the navigation stack:
[self.delegate addContact:contact withBody:text];
where contact and text are the values the user entered.
One could also use a block instead of a delegate but the principle is the same -- have the second view controller only be responsible for taking input, in your case, and pass it back to the view controller managing the data.
Alternatively for delegate suggest using the following:
ViewControllerA.h:
#property (nonatomic, strong) ViewControllerB* viewControllerB;
In ViewControllerA.m
if (!self.viewControllerB)
{
self.viewControllerB = [[ViewControllerB alloc] initWithNibName: #"ViewControllerBr" bundle: nil];
}
[self.navigationController pushViewController: self.viewControllerB
animated: YES];
...
- (void) viewWillAppear: (BOOL) animated
if (self.viewControllerB)
{
NSString* contact = self.viewControllerB.contact;
NSLog(#"%#", contact);
}
...
I'm doing a exercise that making 1 BookStore.
My book store will show all the book object in bookstore array.
My project can be understand like this:
MasterView: will show all title of the book.
DetailView: will show detail of the book whenever users tab on title book at MasterView.
My problem: I want to add one more book at the MasterView by tapping on Add button.
After adding, it should back to MasterView and show all title of book in store again (including the new book that I have added).
I know I need to create a new subview where users can input new book and need to use delegate to do it. But I'm is new in coding and Xcode, I've read some using delegate example but still cannot apply to UITableView.
Here is my project, I hope you guys can help me to understand and accomplish this.
http://wikisend.com/download/720454/SuperBookStore2.zip
Thank you.
Step1: Make a new file named "LKAddViewController"
Step2: In LKAddViewController.h define the UITextField and UIButton and the delegate method for that like..
#import <UIKit/UIKit.h>
#import "LKBook.h"
#protocol LKAddViewControllerDelegate;
#interface LKAddViewController : UIViewController
#property (nonatomic,strong)IBOutlet UITextField *txtField;
#property (nonatomic) id <LKAddViewControllerDelegate> AddBookDelegate;
#property (strong, nonatomic) IBOutlet UITextField *author;
#property (strong, nonatomic) IBOutlet UITextField *titletxt;
#property (nonatomic,strong)IBOutlet UIButton *submit;
-(IBAction)btnSubmit:(id)sender;
#end
#protocol LKAddViewControllerDelegate <NSObject>
- (void)AddBook:(LKBook *)newObj;
#end
Step3: In LKAddViewController.m write the code for submit button and call the delegate method like..
#implementation LKAddViewController
#synthesize AddBookDelegate;
- (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 from its nib.
}
-(IBAction)btnSubmit:(id)sender{
LKBook *newBook = [[LKBook alloc] init];
newBook.author = self.author.text;
newBook.title = self.titletxt.text;
newBook.desc = self.titletxt.text;
if ([self.AddBookDelegate respondsToSelector:#selector(AddBook:)]) {
[self.AddBookDelegate AddBook:newBook];
}
[self.navigationController popViewControllerAnimated:YES];
}
#end
Step:4 In LKMasterViewController.h import the header file and define the delegate methods like..
#import "LKAddViewController.h"
#interface LKMasterViewController () <LKAddViewControllerDelegate>{
Step5: Replace your insertNewObject method by the below code
- (void)insertNewObject:(id)sender
{
LKAddViewController *obj = [[LKAddViewController alloc]initWithNibName:#"LKAddViewController" bundle:nil];
obj.AddBookDelegate=self;
[self.navigationController pushViewController:obj animated:YES];
// if (!_objects) {
// _objects = [[NSMutableArray alloc] init];
// }
// [_objects insertObject:[NSDate date] atIndex:0];
// NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
// [self.tableView insertRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
step6: Write the below method to add the new object and reload the table.
- (void)AddBook:(LKBook *)newObj{
[myBookStore.BookStore addObject:newObj];
[self.tableView reloadData];
}
Hope this works for you and fulfill your requirements.