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);
}
Related
I have a UIViewController Class. In that class I implement a UIWebView. On that WebView I got data from CocoaHttpServer and loading a html page. In CocoaHTTPServer have a NSObject Class. In that Class I got one method for pop to previous Screen. How to Pop to view controller from NSObject class.
This is my NSObject class
if([[array lastObject] compare:#"back-button-clicked"] == NSOrderedSame) {
[self handleBackActionRequest];
}
-(void)handleBackActionRequest
{
PGSoftApViewController *softAP = [[PGSoftApViewController alloc] initWithNibName:nil bundle:nil];
[softAP webToBackNativeCall];
}
This is in my ViewController class :
-(void)webToBackNativeCall
{
[self.navigationController popViewControllerAnimated:YES];
}
This is not working. I am able to insert webToBackNativeCall method. But its not happening anything.
I have to go back. How can I. Please help me.
In your NSObject.h class add protocol like this
#protocol nsobjectDelegate <NSObject>
-(void)navigateToBackVC;
#end
#interface objectClass:NSObject
//your other code
#property (nonatomic,weak) id<nsobjectDelegate> objDelegate;
#end
In you NSObject .m class
-(void)webToBackNativeCall
{
// this method you already have
// other code if you want
[self.objDelegate navigateToBackVC];
}
In you view controller .h class
#interface objectClass:NSViewcontroller <nsobjectDelegate> // delegate of NSObject include it in VC when you want to call that methods
In you view controller .m file in viewDidLoad or willAppear or DidAppear method initializ object of NSObject class and set delegate
NSObjectClass *objeObject = [[NSObjectClass alloc] init];
objeObject.objDelegate = self;
implement this method
-(void)navigateToBackVC
{
[self.navigationController popViewControllerAnimated:YES];
}
This is general concept of protocol and delegate.
Hope this might help you.
In viewDidLoad of your ViewController
[[myNSOBjectClass alloc] startViewController:self];
In NSObject Class
#interface myNSOBjectClass{
//Global access to the view controller.
UIViewController *viewController;
}
#implementation myNSOBjectClass
//function that the caller calls to pass their UIViewController
- (void)startViewController:(UIViewController *)callerViewController{
viewController = [[UIViewController alloc]init];
//puts the caller's view controller to the global member.
viewController = callerViewController;
}
I have this problem that I want to hide the container view from the parent VC when I tap a table cell at the last VC on the right.
I tried hooking up a protocol delegate but it did not work.
Here is my failed attempt:
I added the Protocol on the GOCategoryMenuViewController.
#protocol GOCategoryMenuViewControllerDelegate <NSObject>
-(void)hideMenu;
#end
#interface GOCategoryMenuViewController : UIViewController
#property(weak, nonatomic) id <GOCategoryMenuViewControllerDelegate> delegate;
#end
Implement hideMenu in the .m file
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[self.delegate hideMenu];
}
Import the header and delegate to the parentVC
#import "GOCategoryMenuViewController.h"
#interface ViewController : UIViewController<GOCategoryMenuViewControllerDelegate>
Implement the hideMenu in the .m of ParentVC
-(void)hideMenu
{
NSLog(#"Hide the menu");
}
I believe I need to also declare self on the delegate, but I don't know how and I tried searching for a solution on the web to no avail. It's why I'm asking directly now to you all. Please help and thanks!
Your protocols is true, only thing you have to do is when you init instance of GOCategoryMenuViewController you should give it a delegate sth like this:
GOCategoryMenuViewController *category = [[GOCategoryMenuViewController alloc] init];
//if you don't give delegate, never your delegate method will get called
category.delegate = self;
You have to delegate your instance of GOCategoryMenuViewController class.
If you want to solve it with delegates only, then you must pass the parent view controllers controls delegates to the child view controllers with declaring the properties that has the same type with the parent control in the child view controller. Then you can do any operation on the parent view's control in the child view controller.
ParentViewController.h class
#interface ParentViewController : UIViewController
{
NSMutableDictionary *dictOfPeople;
}
#property(nonatomic, retain) NSMutableDictionary *dictOfPeople;
ParentViewController.m class
#synthesize dictOfPeople;
- (void)anyMethod
{
//initialize child view controller
ChildViewController *childViewController = [[ChildViewController alloc] init];
// here is important
childViewController.owner = self;
}
ChildViewController.h class
#interface ChildViewController : UIViewController
{
id owner;
}
#property(nonatomic, assign) id owner;
ChildViewController.m class
#synthesize owner;
- (void)anyMethod
{
// You can access parent view controllers dictOfPeople dictionary like this
int totalNum = [((ParentViewController *)self.owner).dictOfPeople count];
//...
}
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
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 am trying to pass some data back to my UIView, its abit of a complicated situation I will try to explain it.
I have my
mainViewController // request is made to RequestClass
requestClass // Request is sent off to DB for data, data is returned then passed to seriesDataClass
seriesDataClass // sorts the data and then sends back the needed info to mainViewController using protocol & delegates
This is what my code looks like for setting up the protocols and delegates
mainViewController.h
#import "SeriesDataClass.h"
#interface MatchingSeriesViewController : UIViewController <GetSeriesViewParsedData>
{
mainViewController.m
#import "SeriesDataClass.h"
// this is where I set up my protocols delegate.
- (void)viewDidLoad
{
//..
// get delegate ready
SeriesDataClass *seriesDataClass = [[SeriesDataClass alloc] init];
[seriesDataClass setDelegate:self];
//..
// pass data over to requestClass so you can get the info from the DB
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
//..
[requestClass GetSeries:requestID];
//..
}
requestClass.m
// dose a bunch of stuff then calls seriesDataClass and passes all of its information over to it
//..
SeriesDataClass *seriesDataClass = [[SeriesDataClass alloc] init];
[seriesDataClass recivedData:uncompressedData];
//..
seriesDataClass.h
#import <Foundation/Foundation.h>
// This passes data back to the mainViewController
#protocol GetSeriesViewParsedData <NSObject>
- (void)sendGetSeriesArrays:(NSDictionary *)series LSeries:(NSDictionary *)lSeries;
#end
#interface SeriesDataClass : NSObject <NSXMLParserDelegate> {
//..
}
#property (assign, nonatomic) id <GetSeriesViewParsedData> delegate;
seriesDataClass.m
#implementation SeriesDataClass
#synthesize delegate;
// then in a method later on i call the delegate to pass the information back to mainViewController but this dosnt do anything atm.
//..
[self.delegate sendGetSeriesArrays:seriesDictionary LSeries:lSeriesDictionary];
//..
mainViewController.m
// then back in the mainViewController class I Have the method
- (void)sendGetSeriesArrays:(NSDictionary *)series LSeries:(NSDictionary *)lSeries {
// this method is never accessed
}
So my question is what am i missing in the set up of this protocol/delgate for it not to be working correctly?
I hope the structure of the question makes sense if you need any more information please let me know.
Your problem is that you are creating 2 instances of your SeriesDataClass, one in MainViewController, and another in RequestClass. So, the instance that calls the delegate method is not the same instance that the main view controller set itself as the delegate of. When you create an instance of RequestClass in MainViewController, you need to pass seriesDataClass (the instance you created) to a property in RequestClass, so that it will be working with the same instance.
You should create a property in MainViewController:
#property (strong,nonatomic) SeriesDataClass *seriesDataClass;
The viewDidLoad method should then look like this:
- (void)viewDidLoad {
self.seriesDataClass = [[SeriesDataClass alloc] init];
[self.seriesDataClass setDelegate:self];
}
Then in didSelectRowAtIndexPath, create your RequestClass instance, and pass it seriesDataClass:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
RequestClass *requestClass = [[RequestClass alloc] init];
requestClass.seriesDataInstance = self.seriesDataClass;
[requestClass GetSeries:requestID];
}
In the .h of RequestClass you need to have created that property:
#property (strong,nonatomic) SeriesDataClass *seriesDataInstance;
Then in RequestClass, this:
SeriesDataClass *seriesDataClass = [[SeriesDataClass alloc] init];
[seriesDataClass recivedData:uncompressedData];
should be replaced with just:
[self.seriesDataInstance recivedData:uncompressedData];
I've changed some of the capitalization, to reflect the way you should do it. Classes should start with capital letters, and instances and methods should start with lowercase ones.
Change this:
#import "SeriesDataClass.h"
// this is where I set up my protocols delegate.
- (void)viewDidLoad
{
//..
// get delegate ready
SeriesDataClass *seriesDataClass = [[GetSeriesResultItem alloc] init];
[seriesDataClass setDelegate:self];