I am having a hard time communicating data between two view controllers that are inside a UISplitViewController. I am following this tutorial. I was able to create a split view controller with UITableViews on both master and detail views. Now, What I really want is that when I tap on a particular row in the master table, it has to send some value to the detail view.
I am just playing around with a custom delegate to pass some value from one view controller to another to see if there is any communication between them but nothing seems to work any way.
In MasterTableView.h
#protocol sendingProtocol <NSObject>
-(void)passSomeValue:(NSString *)someValue;
#end
#interface MasterTableView : UITableViewController
{
NSArray *menuArray;
id<sendingProtocol>delegate;
}
#property (nonatomic,assign) id<sendingProtocol>mydelegate;
#end
Synthesized in .m file.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[[self mydelegate] passSomeValue:#"Some Value"];
}
In DetailTableView.h
-(void)passSomeValue:(NSString *)someValue
{
NSLog(#"%#", someValue);
}
Please note that I am calling the mydelegate inside the ViewDidLoad method. Is this the write way? Can someone help?
- (void)viewDidLoad
{
[super viewDidLoad];
MasterTableView *masterView = [[MasterTableView alloc] init];
masterView.mydelegate = self;
}
Thank you in advance!
In viewDidLoad method of your DetailTableView you should not create a new MasterTableView object. The error is here in this method:
- (void)viewDidLoad
{
[super viewDidLoad];
MasterTableView *masterView = [[MasterTableView alloc] init];
masterView.mydelegate = self;
}
You are creating another object of MasterTableView and setting its delegate to self and hence all the problem.
To set the delegate of MasterTableView to DetailTableView, go to AppDelegate.h. You must have defined the MasterTableView and DetailTableView objetcs in AppDelegate.
//Set the DetailTableView as the master's delegate.
self.masterTableView.delegate = self.detailTabelView;
Related
Look at the following code.
In CusFormViewController.h
#interface CusFormViewController : CusBaseViewController
#protocol CusFormViewControllerDelegate <NSObject>
-(void)ticketCreated:(NSString*)ticketID;
-(void)ticketFormRenderingFinished;
#end
#property (nonatomic, weak) id<CusFormViewControllerDelegate> delegate;
In CusFormViewController.m
if ([self.delegate respondsToSelector:#selector(ticketFormRenderingFinished)])
[self.delegate ticketFormRenderingFinished];
if ([self.delegate respondsToSelector:#selector(ticketCreated:)])
[self.delegate ticketCreated:ticket_id];
In ViewController.m
#import "CusFormViewController.h"
#interface ViewController ()<CusFormViewControllerDelegate>
- (void)viewDidLoad {
[super viewDidLoad];
CusFormViewController *formVC = [[CusFormViewController alloc] init];
[formVC setDelegate:self];
}
-(void)ticketCreated:(NSString*)ticketID{
NSLog(#"ticket created.");
}
-(void)ticketFormRenderingFinished{
NSLog(#"ticket form rendered.");
}
The ticketCreated & ticketFormRenderingFinished are not being called.
Most common reason for delegate method not being called is dealing with incorrect objects.
Ensure that CusFormViewController object created from
ViewController is the same which you are presenting on screen and
that the delegate is being set on the same object. I truly believe
you are creating a new CusFormViewController object and setting
delegate on that.
In CusFormViewController, before calling delegate, check the
existence of delegate as well. This is a safety check, you can also put a
NSLog statement to double check if your delegate exists or not. You
are failing here.
If you are segueing from ViewController to CusFormViewController then you set delegate in prepareForSegue: and not in viewDidLoad.
As a side note, put a NSLog statement in viewDidLoad of your CusFormViewController and print self.delegate to check the property setting.
Your controller formVC is dealloced after the function viewDidLoad executed. Create strong reference on your formVC for example like this:
#interface ViewController ()<CusFormViewControllerDelegate>
{
CusFormViewController *_formVC;
}
- (void)viewDidLoad {
[super viewDidLoad];
_formVC = [[CusFormViewController alloc] init];
[formVC setDelegate:self];
}
Hey try to create instance of CusFormViewController using below method
CusFormViewController * _formVC=[[UIStoryboard storyboardWithName:storyboardName bundle: nil]instantiateViewControllerWithIdentifier:#"IDENTIFIER_OF_YOUR_ CusFormViewController"];
This question already has answers here:
Passing data between view controllers
(45 answers)
Closed 8 years ago.
This is a Q&A Style Post
If I want to pass parameters, such as an NSString, NSArray, or NSDictionary, from one view controller to another, what is the easiest way to do this?
There are multiple ways to achieve this, but two of the cleanest methods would involve passing the parameter(s) into a custom init method for the next view controller, or setting the parameter(s) as a property of the next view controller.
Note that this is not restricted to passing data between view controllers - view controllers are objects and any objects can use the following principles, I'm simply using view controllers for the following examples.
Both of these examples are using a simple UITableViewController as the initial view controller, and the next view controller will be passed the user's selection from a list of cells where they can choose their favorite color, as well as the current date of their selection. This can be done FROM any type of view controller TO any type of view controller with a few minor modifications, and within reason there's really no limit to the types/quantity of information that can be passed this way.
keep in mind that you likely don't want a massive initializer method with 10 parameter names, so in that case you might want to have individual properties and set each one accordingly. You also might want to keep the initialization/setup code to a single line if there's only a few parameters, so using a custom initializer method might be for you in that case.
Demo table view setup
#import "TestTableViewController.h"
#import "NextViewController.h"
#interface TestTableViewController ()
#end
#implementation TestTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.colors = #[#"Red", #"Orange", #"Yellow", #"Green"];
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.colors.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ColorCell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"ColorCell"];
}
cell.textLabel.text = self.colors[indexPath.row];
return cell;
}
Method #1 - Custom Initializer
NextViewController.h
#import <UIKit/UIKit.h>
#interface NextViewController : UIViewController
// expose the custom initializer so other view controller's can pass in the parameters we want to pass
- (instancetype)initWithFavoriteColor:(NSString *)favoriteColor currentDate:(NSDate *)date;
#end
NextViewController.m
#import "NextViewController.h"
#implementation NextViewController
// implement the custom initializer method
- (instancetype)initWithFavoriteColor:(NSString *)favoriteColor currentDate:(NSDate *)date {
self = [super init];
// do whatever you want here with the favorite color string and current date that
// was passed in, such as save them to instance variables...
return self;
}
#end
Implement method #1 in our demo table view:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// get the color they selected for this row from our data source array
NSString *selectedColor = self.colors[indexPath.row];
// initialize the next view controller using the handy init method we created
NextViewController *nextVC = [[NextViewController alloc] initWithFavoriteColor:selectedColor currentDate:[NSDate date]];
[self.navigationController pushViewController:nextVC animated:YES];
}
Method #2 - Creating/Setting Properties
NextViewController.h
#import <UIKit/UIKit.h>
#interface NextViewController : UIViewController
#property (nonatomic, retain) NSString *favoriteColor;
#property (nonatomic, retain) NSDate *currentDate;
#end
NextViewController.m
#import "NextViewController.h"
#implementation NextViewController
- (void)viewDidLoad {
[super viewDidLoad];
// do something here with your properties - by the time the view has loaded
// they will have been set/passed from the original view controller
self.favoriteColor...
self.currentDate...
}
#end
Implement method #2 in our demo table view:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// get the color they selected for this row from our data source array
NSString *selectedColor = self.colors[indexPath.row];
// initialize the next view controller normally, and set its favorite color property
// to be what the user selected
NextViewController *nextVC = [NextViewController new];
nextVC.favoriteColor = selectedColor;
nextVC.currentDate = [NSDate date];
[self.navigationController pushViewController:nextVC animated:YES];
}
In both instances, you have now quickly and easily passed multiple pieces of information from one view controller to another.
I want to create a custom tableView class, Which can be used in any view Controller. I have to just create tableview object and set an array and frame of tableview . Then this tableview will be add as subview on my view. and also give me a click event.
I just want to avoid writing tableview datasource and delegate method in every viewController class.
Take a viewController or tableviewController class and code all the delegates and data source methods there. now in you view controller where you want to make it as a subview call the tableview class and add it as a subview.
EX:
TableviewContrller *libaray =[TableviewContrller new];
[libaray willMoveToParentViewController:self];
[self.view addSubview:libaray.view];
[self addChildViewController:libaray];
To hide write this code in your tableview controller class
[self.view removeFromSuperView];
As you are using a reusable class you need to send the array information to that class. along with it it will be better to send either class name or setting tag value to tableview
So in your tableview class write this
-(id)initWithInformationArray :(NSMutableArray *)dataArray andTagValueforTableview :(int) tagValue
{
self = [super init];
if (self != nil)
{
NSLog(#"%#", dataArray);
}
return self;
}
Now sub viewing will be like this
TableviewContrller *libaray =[[TableviewContrller alloc]initWithInformationArray:YOURARRAY andTagValueforTableview:TAGVALUE];
[libaray willMoveToParentViewController:self];
[self.view addSubview:libaray.view];
[self addChildViewController:libaray];
Hope this will help.
May be you can use UITableViewController.
UITableViewController is a subclass of UIViewController, when you create a subclass of UITableViewController, the template has the usual methods of tableview datasource and delegate methods.
You'll need to create a custom class and create your own delegate in that class for UITableView. Now whenever you create a UITableView assign that custom class as the class for UITableView.
If you don't know how to create custom delegates then check below links:
http://www.alexefish.com/post/522641eb31fa2a0015000002
http://ios-blog.co.uk/tutorials/quick-tip-create-your-own-objective-c-delegate-protocol/
Hope this will help you :)
You can create BaseTableView class.
#interface BaseTableView : UITableView <UITableViewDelegate, UITableViewDataSource>
{
NSArray* listObject;
}
#property (nonatomic, retain) NSArray *listObject;
-(id) initWithFrame:(CGRect)frame style:(UITableViewStyle)style;
#end
#implementation BaseTable
#synthesize listObject;
-(id) initWithFrame:(CGRect)frame style:(UITableViewStyle)style
{
if(self = [super initWithFrame:frame style:style])
{
self.dataSource = self;
self.delegate = self;
}
return self;
}
-(void)setListObject:(NSArray *)listObjectRef
{
[listObject release];
listObject = [listObjectRef retain];
[self reloadData];
}
-(void) dealloc
{
[listObject release];
[super dealloc];
}
#end
Inherit this class for specific use and override following methods according to needs
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath;
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
In your ViewController class use following code
SpecificTableView *table = [[SpecificTableView alloc] init];
[table setListObject:((FRFTReportList*)obj)];
Hopefully this will help.
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];
I am trying to make a custom protocol that i hope somebody might help with.
I have a mainViewController (mainVC) that has a label. That label needs to be updated with a string when i press a button in edwwVC.
I am using ARC and storyboard.
The problem is when i press the Done Button on the edwwVC, the "done" method is called BUT the delegate method is not called in mainVC.
Whereas, if i call the done method VIA the mainVC, then the done method is called AND the delegate method. So I can see the connection is there, I just do not understand why the delegate method is not called when i press the done button in the edwwVC.
I imagine it has something to do with the init of the edwwVC. Because it is already initiated by storyboard, so it looks to me as if I am initializing it again the in the viewDidLoad method of the mainVC. But that is how far i got :)
Thanks in advance!
edwwVC.h
#import <UIKit/UIKit.h>
#import "IIViewDeckController.h"
#class EDWWViewController;
#protocol EDWWViewControllerDelegate <NSObject>;
#optional
- (void)edwwVCDidFinish:(EDWWViewController *)edwwVC;
#end
#interface EDWWViewController : UIViewController <IIViewDeckControllerDelegate> {
__weak id<EDWWViewControllerDelegate> delegate;
NSMutableArray *edwwPoints;
}
#property (weak) id<EDWWViewControllerDelegate> delegate;
#property (weak, nonatomic) IBOutlet UITableView *theTableView;
#property (strong, nonatomic) NSString *testString;
- (IBAction)done:(id)sender;
- (IBAction)add:(id)sender;
#end
edwwVC.m:
#pragma mark - delegate method
- (IBAction)done:(id)sender {
testString = #"This is the test string!";
[delegate edwwVCDidFinish:self];
[self.viewDeckController closeRightViewAnimated:YES];
NSLog(#"Done pressed");
}
MainVC.m:
- (void)viewDidLoad
{
[super viewDidLoad];
edwwViewController = [[EDWWViewController alloc] init];
edwwViewController.delegate = self;
}
- (void)edwwVCDidFinish:(EDWWViewController *)edwwVC {
edwwLabel.text= edwwVC.testString;
NSLog(#"delegate method called");
}
Remove the line ...
__weak id<EDWWViewControllerDelegate> delegate;
From the .h and change the line...
[delegate edwwVCDidFinish:self];
to...
[self.delegate edwwVCDidFinish:self];
In the .m.
That should sort it.
The way you have it set up the ivar delegate is not the same as the property delegate (which is actually an ivar called _delegate) (thanks #Joris Kluivers, just adding for clarity). They are pointing to different things.
If you add a breakpoint where you are calling the delegate method I think you'll find that delegate is nil. Whereas _delegate (or self.delegate) is not nil.
::EDIT::
Ahh... just spotted the second bit too.
If you are setting up the edwwvc in storyboard then you should be alloc initing it too.
If you are segue-ing to the edwwvc then you should intercept the segue in mainVC.m like this...
- (void)prepareForSegue: //blah the rest of the name...
{
if ([segue.identifier isEqualToString:#"the name of your segue"])
{
EDWWViewController *controller = segue.destinationViewController;
controller.delegate = self;
}
}
This will take the controller that you are pushing to from the storyboard and set the delegate to it.
:: ANOTHER EDIT ::
If EDWWVC is inside a containerViewController then you can do this inside viewDidLoad in MainVC.m...
- (void)viewDidLoad
{
// other stuff...
for (UIViewController *controller in self.childViewControllers) {
if ([controller isKindOfClass:[EDWWViewController class]]) {
EDWWViewController *edwwvc = (EDWWViewController*)controller;
eddwvc.delegate = self;
}
}
}
You may find this code has to go in viewDidAppear or something but I think viewDidLoad shouldd work just fine.
You may actually be able to set the delegate property directly by using the storyboard to (but I'm not 100% certain on this).
The answer was in the containerVC of both controllers.
Where i initialized the view controllers: the viewDidLoad of the containerVC m file:
- (void)viewDidLoad
{
[super viewDidLoad];
mainVC = (MainViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"MainVC"];
edwwVC = (EDWWViewController *)[self.storyboard instantiateViewControllerWithIdentifier:#"EDWWVC"];
//THIS LINE WAS MISSING
edwwVC.delegate = mainVC;
self.centerController = mainVC;
self.rightController = edwwVC;
}
BUT guys thanks for the help! :) Appreciate it got me in the right direction! :) THANKS! :)