A weird situation arises while using delegates in iOS.
A delegate method send its control to different class rather than calling class implemented same delegate method.
Example :
I am having a Dashboard which is calling a web service (a different class implemented all web service calls). In dashboard global web service class object exists with delegate self. When we call a web service the control comes to this class. So thats fine.
Now i am having another class which got push from dashboard or some time from other view controllers as well and it is also calling same web service. It is having its own web service class object globally and set delegate to self.
When I am calling web service from this class with its web service object after web service call control goes to delegate of dashboard not to this class though call has been made from this class and delegation is set to self.
This situation arises to many place where pushed child also implemented the same delegate method which its previous class has also implemented and thus instead delegation called of pushed class the method is called of the previous class.
Here is the main lines of code explaining above example :
WebServiceCaller.h
Class handles all web services caller
#import <Foundation/Foundation.h>
#import "WebserviceEnum.h"
#protocol WebServiceCallerDelegate;
#interface WebServiceCaller : NSObject
{
__unsafe_unretained id <WebServiceCallerDelegate> delegate;
NSOperationQueue * operationQueue;
}
#property(nonatomic, assign) id <WebServiceCallerDelegate> delegate;
-(void)cancelWebserviceCall;
-(void)cancelAllCalls;
#pragma mark - Class Methods
-(void)getListOfAnalyticQuestionsOfUserID:(NSString*)userid;
#end
#pragma mark - Protocol Methods
#protocol WebServiceCallerDelegate <NSObject>
#optional
-(void)getListOfAnalyticQuestionsCompletesSuccessfully:(BOOL)success WithList:(NSMutableArray*)arrQuestions WithMessage:(NSString*)message;
#end
WebServiceCaller.m
When after webservice call result will be sent to calling class.
-(void) getListOfAnalyticQuestionsOfUserID:(NSString*)userid{
NSString *url = [NSString stringWithFormat:#"%#?user_id=%#",[self getURLWithBase:BaseURL relativeURL:#"wt_question.php"],userid];
//webservice call goes here and after completion calls below method
}
-(void)getListOfAnalyticQuestionsCalledSuccessfully:(BOOL)success WithData:(id)Data WithMessage:(NSString*)errorMessage{
NSDictionary *dictResult = (NSDictionary*)Data;
NSMutableArray *arrAnalytics = nil;
NSString *message = errorMessage;
if (success) {
arrAnalytics = [dictResult objectForKey:#"items"];
message = SuccessMessage;
}
else{
if (message.length==0) {
message = NETWORKERRORMESSAGE;
}
}
if(self.delegate!=nil && [(id)[self delegate] respondsToSelector:#selector(getListOfAnalyticQuestionsCompletesSuccessfully:WithList:WithMessage:)])
{
[(id)[self delegate] getListOfAnalyticQuestionsCompletesSuccessfully:success WithList:arrAnalytics WithMessage:message];
}
}
Code snippets from calling class suppose class B, same implementation has been done in class A also from which B has been pushed so every thing is working fine instead of sending control to class B control is sent to class A (webServiceCaller object is created in class A in same manner as in class B and calling same web service, This is just an example same thing happened for other web services too. which is implemented by both pushed and its previous class.)
#import "WebServiceCaller.h"
#define numberOfRecordsPerPage 15
#interface AnalyisViewController ()<UITableViewDataSource,UITableViewDelegate,WebServiceCallerDelegate>
{
NSInteger currentIndex;
NSDictionary *dictQuesList;
NSInteger totalPages;
NSMutableArray *arrQuestionList;
WebServiceCaller *webServiceCaller;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
webServiceCaller = [[WebServiceCaller alloc]init];
webServiceCaller.delegate = self;
[self showQuestions];
}
-(void)showQuestions{
[ProgressHUD show:#"Loading..." Interaction:NO];
[webServiceCaller cancelAllCalls];
[webServiceCaller getListOfAnalyticQuestionsOfUserID:userid];
}
#pragma mark - Webservice delegate
-(void) getListOfAnalyticQuestionsCompletesSuccessfully:(BOOL)success WithList:(NSMutableArray*)arrQuestions WithMessage:(NSString*)message{
//Handles my stuff
}
#end
Any idea of this weird situation.
Related
I have three classes involved in this problem:
my appDelegate
my data class
my my viewcontroller class
when my app launches I use the didFinishLaunchingWithOptions method in my app delegate to create an instance of the data class and then call the queryMessagesFromBackend method to fill my messages array.
Then in my view controller I create another instance of my data class to access the messages array (dataClass.messages) that i just filled, however its empty. This does not make sense because when the method is called it Logs all the data the messages array has. Why is my new instance showing that the messages array is empty?
I would provide code but that seems useless
In yours "app delegate" make first "data class" object an ivar (or property) of "app delegate"
Declare some getter for that data object in app delegate class.
In your's view controller - get app delegate via shared NSApp instance.
Get shared data object from app delegate with introduced getter.
Tip: U can use an interface (protocol) for making things little cleaner:
#protocol XYZDataProvider <NSObject>
- (XYZDataClass *) data;
#end
...
#interface XYZAppDelegate : NSAppDelegate <XYZDataProvider> {
XYZDataClass *data;
}
#end
...
#implementation XYZAppDelegate
// either can init data in didFinishBlahBlahBlah...
- (void) did ... {
self->data = [XYZDataClass new];
...
}
// implement protocol's required method
- (XYZDataClass *) data {
/// and then return on request...
return self->data;
// or do so-caled lazy-loading:
// if (!self->data) {
// $self->data = [... ..];
// ...
// }
// return self->data;
}
#end
...
#implementation XYZViewController
- (void) processData {
NSAppDelegate *appDelegate = [NSApp delegate];
if ([appDelegate conformsToProtocol:#protocol(XYZDataProvider)]) {
XYZDataClass *data = [(id<XYZDataProvider>)appDelegate data];
// do smth with data
...
}
...
}
#end
Note: code contains errors (written directly in browser...)
I have an application where A View Controller (A)is called twice in close succession. Now each time it is called, an NSString object is created, and I need this value to be stored in an NSMutableArray that is a public property of ANOTHER View Controller (B).
In A, I create an instance of the second View Controller (B), and using that instance, add the NSString objects into the NSMutableArray which I've created as a public property. Later, when I am inside View Controller B and print the contents of the NSMutableArray property, the array is empty. Why? Here is the code that is inside View Controller A:
-(void)viewDidLoad {
ViewControllerA *aVC = [[ViewControllerA alloc] init];
if (aVC.stringArray == nil) {
aVC.stringArray = [[NSMutableArray alloc] init];
}
[aVC.stringArray addObject:#"hello"];
[aVC.stringArray addObject:#"world"];
for (NSString *wow in aVC.stringArray) {
NSLog(#"The output is: %#", wow);
}
}
Inside my View Controller B class, I have the following code:
- (IBAction)buttonAction:(UIButton *)sender {
NSLog(#"Button selected");
for (NSString *test in self.stringArray) {
NSLog(#"Here are the contents of the array %#", test);
}
}
Now the buttonAction method gets called, as I do see the line Button selected in the system output, but nothing else is printed. Why? One thing I want to ensure is that View Controller A is called twice, which means I would like to see in the output, "Hello World", "Hello World" (i.e. printed twice), and not "Hello World" printed just once.
The other thing I wish to point out is that View Controller B may not be called at all, or it may be called at a later point in time. In any case, whenever View Controller B is called, I would like to have the values inside the array available, and waiting for the user to access. How do I do this?
Your approach is not ideal, potentially leading to a memory cycle, with two objects holding strong pointers to each other.
You can instead achieve your goal in two ways;
Delegate Protocol
This method allows you to set delegates and delegate methods to pass data back and forth between view controllers
in viewControllerA.h
#protocol viewControllerADelegate <NSObject>
- (void)addStringToNSMutableArray:(NSString *)text;
#end
#interface viewControllerA : UIViewController
#property (nonatomic, weak) id <viewControllerADelegate> delegate;
in viewControllerB.m
// create viewControllerA class object
[self.viewControllerA.delegate = self];
- (void)addStringToNSMutableArray:(NSString *)text
{
[self.mutableArray addObject:text];
}
in viewControllerA.m
[self.delegate addStringToNSMutableArray:#"some text"];
Utility Classes
Alternatively you can use a utility class with publicly accessible methods (and temporary data storage). This allows both viewController classes to access a shared data store, also if you use class methods, you don't even need to instantiate the utility class.
in XYZUtilities.h
#import <Foundation/Foundation.h>
#interface XYZUtilities : NSObject
+ (void)addStringToNSMutableArray;
#property (strong, nonatomic) NSMutableArray *array;
#end
in XYZUtilities.m
+ (void)addStringToNSMutableArray
{
NSString *result = #"some text";
[self.array addObject:result];
}
+ (NSArray)getArrayContents
{
return self.array;
}
in viewControllerA.m
NSString *stringFromObject = [XYZUtilities addStringToNSMutableArray];
in viewControllerB.m
self.mutableArray = [[NSMutableArray alloc] initWithArray:[XYZUtilities getArrayContents]];
I'm not sure what kind of a design pattern you are trying to follow but from the looks of it IMHO that's not a very safe one. However, there are many, many ways this could be accomplished.
One thing though, you said that View Controller B may never get allocated and if it is alloc-ed, it will be down the road. So you can't set a value/property on an object that's never been created.
Since you already aren't really following traditional patterns, you could make a static NSMutableArray variable that is declared in the .m of your View Controller B Class and then expose it via class methods.
So it would look like this:
viewControllerB.h
+(void)addStringToPublicArray:(NSString *)string;
viewContrllerB.m
static NSMutableArray *publicStrings = nil;
+(void)addStringToPublicArray:(NSString *)string{
if (publicStrings == nil){
publicStrings = [[NSMutableArray alloc]init];
}
if (string != nil){
[publicStrings addObject:string];
}
}
Then it would be truly public. All instances of view controller B will have access to it. This, of course is not a traditional or recommended way of doing it—I'm sure that you will have many replies pointing that out ;).
Another idea would be to use a singleton class and store the values in there. Then, when or if view controller B is ever created, you can access them from there.
I have three UIViewController that call a method in another Class, when there is need.
This fourth Class subclass of NSObject, which I will call CheckController, it makes a connection to a database on a server, and to do this takes a few seconds.
I have two questions to ask:
-FIRST: now to get the array back to me from the server, use a method that is almost embarrassing for me to share (bad code for me),
so i need to know how to call this CheckController and return a value in the ViewController from which the call originated.
-SECOND: how do I know in CheckController, from which UIViewController, the method was invoked?
this is code of CheckController:
-(void)connectionWithString:(NSString *)string {
//connection with server - work well
}
...
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
...
[self returnArray:myObject];
}
-(void)returnArray:(NSMutableArray *)arrayReturn {
//in this method i set the BOOL done to YES, but i believe that is it possible to
//send directly this arrayReturn to ViewController that invoked this method
done = YES;
NSLog(#"arrayReturn = %#", arrayReturn);
}
thanks in advance for the help, and tell me if something is not clear
As you already mentioned your Class is a subclass of NSObject which is good. But you should provide a protocol which calls the delegate if your CheckController receives some data. So in your CheckController.h
#protocol CheckControllerDelegate <NSObject>
#required
- (void)receivedArray:(NSArray*)data
#end
#property (nonatomic, weak) id <CheckControllerDelegate> delegate;
In your ViewController:
[self.CheckController setDelegate:self];
CheckController.m:
-(void)connectionDidFinishLoading:(NSURLConnection *)connection {
[_delegate receivedArray:myObject];
}
For best practice your protocol should also have a method which would be called if an error occurs.
I have a question about passing data in iOS/Objective-C. I just started creating an app that connects and fetches data from a website, and now I'm having a problem.
My default and root view controller is called ViewController. It has the basic login UI views: 2 textfields and a button.
When the button has been clicked/touched, the ViewController calls a method from another class called LoginService. Now LoginService handles the connection to the website. I have no problem connecting to the website and fetching data from it, but I have a problem returning the fetched data, now processed as an NSDictionary, to the ViewController.
The first thing I tried was to create a setter method in the ViewController that sets the instance variable userProfile to the NSDictionary passed into it. It failed, however. I tried using it in the NSURLConnectionDataDelegate method connectionDidFinishLoading from the LoginService.
This might be a silly question, but I have no idea how can I pass the fetched NSDictionary from LoginService to the ViewController after the button is clicked. Do I need blocks, queue, or something else? I mean, for example, I need to set a label below my login button to the name of the user who logged in. How can I perform this?
Hope someone can help me. I'd greatly appreciate it.
As danh has explained blocks pattern for doing this, I will try to explain the delegating pattern. The steps for making this work:
In LoginService.h
Create a protocol definition in your LoginService like this:
#protocol LoginServiceDelegate
-(void)applicationLoggedIn:(NSMutableDictionary*) responseData;
#end
Now add a member pointer holding this delegate and add a property for this
#interface LoginService {
id<LoginServiceDelegate>delegate;
}
#property (nonatomic, assign) id <LoginServiceDelegate> delegate;
In LoginService.m
Once you got the response for login in connectionDidFinishLoading, just invoke the delegate method like below:
if ([delegate respondsToSelector:#selector(applicationLoggedIn:)]) {
[delegate applicationLoggedIn:responseDict];
}
In LoginViewController.h
Now to use this in your LoginViewController, you need to implement this protocol
#import "LoginService.h"
#interface LoginViewController<LoginServiceDelegate>
In LoginViewController.m
Assign the delegate of LoginService to LoginViewController
LoginService* loginService = [[LoginService alloc]init];
loginService.delegate = self;
Implement the protocol method as:
-(void)applicationLoggedIn:(NSDictionary*)response{
}
Hope this helps.
Two patterns to consider: delegate and block. Block is quicker to code, and I usually prefer it to delegate for network ops. To use a block, write the login service this way:
// LoginService.h
- (void)login:(NSString *)username completion:(void (^)(NSDictionary *, NSError *))completion;
It sounds like you're using NSURLConnection delegate pattern here, so I will assume that. Please realize that NSURLConnection also provides a nice one-shot block method to do the request.
// LoginService.m
#property (copy, nonatomic) void (^completion)(NSDictionary *, NSError *);
- (void)login:(NSString *)username completion:(void (^)(NSDictionary *, NSError *))completion {
// copy the block when the request begins
self.completion = completion;
// start your request, as you have it now
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSDictionary *dictionary = // parse the data you collected into a dictionary
// invoke the block with the result
self.completion(dictionary, nil);
self.completion = nil;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
self.completion(nil, error);
self.completion = nil;
}
It's polite to dispose of the block (set it to nil) after you invoke it, so it doesn't retain any part of the calling context.
Basically you need ViewController to have a public method which LoginService can call when it's done its job, and NSDictionary will be a parameter to this method. LoginService will need a reference back to ViewController in order to invoke this method, so define a public property on LoginService which will hold a ViewController reference - and set this right after instantiating LoginService.
Of course, if you want LoginService to be more reusable, and not tied to ViewController specifically, delegates are the way to go. LoginService would define the LoginServiceDelegate protocol with the method to be called on completion. ViewController would then implement the LoginServiceDelegate protocol. The public property on LoginService becomes a LoginServiceDelegate reference, and so LoginService no longer needs to import ViewController. This way, ViewController is dependent on LoginService, but LoginService is not dependent on ViewController.
What is the best way to pass data from a child modal view to the parent view controller?
I have a Child Modal Login Screen on my iPad app that I want to pass back user information to the parent Split View Controller.
I am thinking of using NSNotification, but I am not sure if this is the easiest/most efficient way to pass data back to the parent.
Thanks!
Alan
I would suggest, as iPatel did, to use delegation to solve your problem. The relationship between the parent view controller and the login view controller makes this pattern appropriate. When one object creates another in order to fulfill a specific responsibility, one should consider delegation as a way to have the created object communicate with the creator. A particularly compelling reason to choose delegation would be if the task to be accomplished potentially has multiple steps that require a high level of interaction between objects. You can look at the NSURLConnectionDelegate protocol as an illustration of this. Connecting to a URL is a complex task, involving stages such as processing responses, meeting authentication challenges, saving downloaded data, and handling errors, the connection and the delegate handle this together over the lifetime of the connection.
As you've probably noticed, in Objective-C protocols are used to achieve delegation without tightly coupling the created object (in this case your login view controller) to the object that created it (the parent view controller). The login view controller can then interact with any object that can receive the messages defined in its protocol, rather than rely on any particular class implementation. Tomorrow, if you receive a requirement to allow any view controller to show the login view, the login view controller wouldn't need to change. Your other view controllers can implement its delegate protocol, create and present the login view, and assign themselves as delegates without the login view controller ever knowing of their existence.
Some delegation examples you'll find on Stack Overflow may be very confusing and very un-like what's found in the built-in frameworks. One must pick the names and interfaces of the protocols carefully, as well as the responsibilities assigned to each object, so that code reuse is maximized and the objective of the code is achieved.
You should first take a look at the many delegate protocols within the built-in frameworks for an idea of what the relationship looks like when expressed in code. Here is another small example, based on your login use case. I hope you will find that the purpose of the delegation is clear and that the roles and responsibilities of the objects involved are clear and expressed through their names within the code.
First, let's look at the LoginViewController's delegate protocol:
#import <UIKit/UIKit.h>
#protocol LoginViewControllerDelegate;
#interface LoginViewController : UIViewController
// We choose a name here that expresses what object is doing the delegating
#property (nonatomic, weak) id<LoginViewControllerDelegate> delegate;
#end
#protocol LoginViewControllerDelegate <NSObject>
// The methods declared here are all optional
#optional
// We name the methods here in a way that explains what the purpose of each message is
// Each takes a LoginViewController as the first argument, allowing one object to serve
// as the delegate of many LoginViewControllers
- (void)loginViewControllerDidLoginSuccessfully:(LoginViewController *)lvc;
- (void)loginViewController:(LoginViewController *)lvc didFailWithError:(NSError *)error;
- (void)loginViewControllerDidReceivePasswordResetRequest:(LoginViewController *)lvc;
- (void)loginViewControllerDiDReceiveSignupRequest:(LoginViewController *)lvc;
- (BOOL)loginViewControllerShouldAllowAnonymousLogin:(LoginViewController *)lvc;
#end
The login controller can communicate a number of events to its delegate, as well as ask its delegate for information used to customize its behavior. It communicates events to the delegate in its implementation as part of its response to user actions:
#import "LoginViewController.h"
#interface LoginViewController ()
#property (weak, nonatomic) IBOutlet UIButton *anonSigninButton;
#end
#implementation LoginViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Here we ask the delegate for information used to layout the view
BOOL anonymousLoginAllowed = NO;
// All our protocol methods are #optional, so we must check they are actually implemented before calling.
if ([self.delegate respondsToSelector:#selector(loginViewControllerShouldAllowAnonymousLogin:)]) {
// self is passed as the LoginViewController argument to the delegate methods
// in this way our delegate can serve as the delegate of multiple login view controllers, if needed
anonymousLoginAllowed = [self.delegate loginViewControllerShouldAllowAnonymousLogin:self];
}
self.anonSigninButton.hidden = !anonymousLoginAllowed;
}
- (IBAction)loginButtonAction:(UIButton *)sender
{
// We're preteneding our password is always bad. So we assume login succeeds when allowed anonmously
BOOL loginSuccess = [self isAnonymousLoginEnabled];
NSError *loginError = [self isAnonymousLoginEnabled] ? nil : [NSError errorWithDomain:#"domain" code:0 userInfo:nil];
// Fake concurrency
double delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// Notify delegate of failure or success
if (loginSuccess) {
if ([self.delegate respondsToSelector:#selector(loginViewControllerDidLoginSuccessfully:)]) {
[self.delegate loginViewControllerDidLoginSuccessfully:self];
}
}
else {
if ([self.delegate respondsToSelector:#selector(loginViewController:didFailWithError:)]) {
[self.delegate loginViewController:self didFailWithError:loginError];
}
}
});
}
- (IBAction)forgotPasswordButtonAction:(id)sender
{
// Notify delegate to handle forgotten password request.
if ([self.delegate respondsToSelector:#selector(loginViewControllerDidReceivePasswordResetRequest:)]) {
[self.delegate loginViewControllerDidReceivePasswordResetRequest:self];
}
}
- (IBAction)signupButtonAction:(id)sender
{
// Notify delegate to handle signup request.
if ([self.delegate respondsToSelector:#selector(loginViewControllerDiDReceiveSignupRequest:)]) {
[self.delegate loginViewControllerDiDReceiveSignupRequest:self];
}
}
- (BOOL)isAnonymousLoginEnabled
{
BOOL anonymousLoginAllowed = NO;
if ([self.delegate respondsToSelector:#selector(loginViewControllerShouldAllowAnonymousLogin:)]) {
anonymousLoginAllowed = [self.delegate loginViewControllerShouldAllowAnonymousLogin:self];
}
return anonymousLoginAllowed;
}
#end
The main view controller instantiates and presents a login view controller, and handles its delegate messages:
#import "MainViewController.h"
#import "LoginViewController.h"
#define LOGGED_IN NO
#interface MainViewController () <LoginViewControllerDelegate>
#end
#implementation MainViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Fake loading time to show the modal cleanly
if (!LOGGED_IN) {
double delayInSeconds = 1.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// Create a login view controller, assign its delegate, and present it
LoginViewController *lvc = [[LoginViewController alloc] init];
lvc.delegate = self;
[self presentViewController:lvc animated:YES completion:^{
NSLog(#"modal completion finished.");
}];
});
}
}
#pragma mark - LoginViewControllerDelegate
- (void)loginViewControllerDidLoginSuccessfully:(LoginViewController *)lvc
{
NSLog(#"Login VC delegate - Login success!");
[self dismissViewControllerAnimated:YES completion:NULL];
}
- (void)loginViewController:(LoginViewController *)lvc didFailWithError:(NSError *)error
{
// Maybe show an alert...
// UIAlertView *alert = ...
}
- (void)loginViewControllerDidReceivePasswordResetRequest:(LoginViewController *)lvc
{
// Take the user to safari to reset password maybe
NSLog(#"Login VC delegate - password reset!");
}
- (void)loginViewControllerDiDReceiveSignupRequest:(LoginViewController *)lvc
{
// Take the user to safari to open signup form maybe
NSLog(#"Login VC delegate - signup requested!");
}
- (BOOL)loginViewControllerShouldAllowAnonymousLogin:(LoginViewController *)lvc
{
return YES;
}
#end
Logging in can be a complex, interactive process in some ways, so I do recommend you seriously consider using delegation instead of notifications. However, one thing that may be problematic is that delegates are necessarily only a single object. If you need to have multiple, disparate objects know about the login view controller's progress and stae, then you may need to use notifications. Especially if the login process can be constrained to be very simple, in a way that does not require any interaction beyond passing one-way messages and data, then notifications can become a viable option. You can pass arbitrary variables in a notification back inside the userInfo property which is an NSDictionary of whatever you decide to stuff in it. Notifications can impact performance but I understand that only happens nowadays when observers number in the hundreds. Even still, it is not the most natural fit in my mind, as you have the parent object (that more or less controls the lifetime of the child) asking a third party object for updates from the child object.
You can get it by using Protocol, it is Best way.
I will give you the Basic Idea for how to create a Protocol
Also, read this question:
How do I create delegates in Objective-C?
Following code give you the basic idea for Protocol, here in below code you can get Button title from MasterViewController to DetailViewController.
#DetailViewController.h
#import <UIKit/UIKit.h>
#protocol MasterDelegate <NSObject>
-(void) getButtonTitile:(NSString *)btnTitle;
#end
#interface DetailViewController : MasterViewController
#property (nonatomic, assign) id<MasterDelegate> customDelegate;
#DetailViewController.m
if([self.customDelegate respondsToSelector:#selector(getButtonTitile:)])
{
[self.customDelegate getButtonTitile:button.currentTitle];
}
#MasterViewController.m
create obj of DetailViewController
DetailViewController *obj = [[DetailViewController alloc] init];
obj.customDelegate = self;
[self.navigationController pushViewController:reportTypeVC animated:YES];
and add delegate method in MasterViewController.m for get button title.
#pragma mark -
#pragma mark - Custom Delegate Method
-(void) getButtonTitile:(NSString *)btnTitle;
{
NSLog(#"%#", btnTitle);
}