Custom delegate method not called - ios

I'm trying to adapt Apple's example of TableViewUpdates (expanding TableView Cells) to my own application, but I can't seem to get it to work.
I tried narrowing the problem down and I think I know where the problem lies now.
Apple uses a UITableViewController as the base controller for the view, but I have a UIViewController that has the UITableViewDelegate and DataSource as delegate methods. I added the HeaderViewDelegate to it like this:
#interface SearchViewController : UIViewController <UITableViewDelegate, UITableViewDataSource, IngredientHeaderViewDelegate>
IngredientHeaderFooterView.h:
#import <Foundation/Foundation.h>
#include <UIKit/UIKit.h>
#protocol IngredientHeaderViewDelegate;
#interface IngredientHeaderFooterView : UITableViewHeaderFooterView
#property (nonatomic, weak) IBOutlet UILabel *lblTitle;
#property (nonatomic, weak) IBOutlet id <IngredientHeaderViewDelegate> delegate;
#property (nonatomic) NSInteger section;
- (void)toggleOpenWithUserAction:(BOOL)userAction;
#end
#protocol IngredientHeaderViewDelegate <NSObject>
#property (nonatomic) NSInteger hoi;
#optional
- (void)sectionHeaderView:(IngredientHeaderFooterView *)sectionHeaderView sectionOpened:(NSInteger)section;
- (void)sectionHeaderView:(IngredientHeaderFooterView *)sectionHeaderView sectionClosed:(NSInteger)section;
#end
In IngredientHeaderFooterView.m:
- (void)toggleOpenWithUserAction:(BOOL)userAction {
if ([self.delegate respondsToSelector:#selector(sectionHeaderView:sectionOpened:)]) {
NSLog(#"Test1");
[self.delegate sectionHeaderView:self sectionOpened:self.section];
}
if ([self.delegate respondsToSelector:#selector(sectionHeaderView:sectionClosed:)]) {
NSLog(#"Test2");
[self.delegate sectionHeaderView:self sectionClosed:self.section];
}
}
And in my UIViewController that implements the delegate:
- (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section {
IngredientHeaderFooterView *ingredientHeaderView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:SectionHeaderViewIdentifier];
IngredientDescriptionInfo *ingredientInfo = (self.sectionInfoArray)[section];
ingredientInfo.headerView = ingredientHeaderView;
ingredientHeaderView.lblTitle.text = ingredientInfo.play.name;
ingredientHeaderView.section = section;
ingredientHeaderView.delegate = self;
return ingredientHeaderView;
}
But respondsToSelector: always returns false. What could it be?

In your SearchViewController, you need to implement both methods from the protocol IngredientHeaderViewDelegate:
- (void)sectionHeaderView:(IngredientHeaderFooterView *)sectionHeaderView sectionOpened:(NSInteger)section
{
NSLog(#"section opened");
}
- (void)sectionHeaderView:(IngredientHeaderFooterView *)sectionHeaderView sectionClosed:(NSInteger)section
{
NSLog(#"section closed");
}
Also, don't forget to actually assign the delegate in IngredientHeaderFooterView. Make sure that it's not nil when toggleOpenWithUserAction: is called.
If you make sure that the methods are implemented and the delegate is actually assigned you should be good :)

Related

How to pass message using delegates from one view controller to another using delegate?

main storyboard imageI have one Table View Controller named "Contacttableviewcontroller" and one View Controller as"Detailviewcontroller". I have 2 text fields in my View Controller to give contact name and number. I have a button to save. When I click on that button, it should display it in Table View Controller. Concept I am using is passing information from destination to source using delegates. Here goes my code which is not working properly.
Detailviewcontroller.h
#protocol detailviewcontrollerdelegate<NSObject>
- (void)additem:(NSString *)Name MOBILE:(NSString *)Mobile;
#end
#interface DetaiViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *nametextfield;
#property (weak, nonatomic) IBOutlet UITextField *mobiletextfield;
- (IBAction)Save:(id)sender;
#property(nonatomic,weak)id<detailviewcontrollerdelegate>delegate;
Detailviewcontroller.m
- (IBAction)Save:(id)sender {
[self.delegate additem:self.nametextfield.text MOBILE:self.mobiletextfield.text];
}
Contacttableviewcontroller.h
#interface ContactTableViewController : UITableViewController<detailviewcontrollerdelegate>
#property(strong,nonatomic)NSString *contactname;
#property(strong,nonatomic)NSString *contactno;
-(void)reloadtabledata;
#property(strong,nonatomic)NSArray *contactnamearray;
#property(strong,nonatomic)NSArray *contactnoarray;
#end
Contacttableviewcontroller.m
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return 4;
}
- (void)additem:(NSString *)Name MOBILE:(NSString *)Mobile
{
self.contactname=Name;
self.contactno=Mobile;
self.contactnamearray=#[self.contactname];
self.contactnoarray=#[self.contactno];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellreuse" forIndexPath:indexPath];
cell.textLabel.text=[_contactnamearray objectAtIndex:indexPath.row];
cell.detailTextLabel.text=[_contactnoarray objectAtIndex:indexPath.row];
return cell;
}
-(void)reloadtabledata
{
[self.tableView reloadData];
}
Firstly, you need to check, if you have attached your action method, -Save: to your button or not. You can attach it through the storyboard or programatically. To do it through storyboard, give your button a name like saveButton(not compulsory) and then attach it by ctrl dragging as usual.
Make sure, you attach all the IBOutlets through storyboard properly.
P.S: I have updated the variable's name with proper naming convention. You should also follow the camel case convention while naming your variables.
here is the DetailViewController.h code-
#import <UIKit/UIKit.h>
#protocol DetailViewControllerDelegate;
#interface DetailViewController : UIViewController
#property (weak, nonatomic) IBOutlet UITextField *nameTextField;
#property (weak, nonatomic) IBOutlet UITextField *mobileTextField;
#property(strong, nonatomic) IBOutlet UIButton *savebutton;
- (IBAction)Save:(id)sender;
#property(nonatomic,weak)id<DetailViewControllerDelegate>delegate;
#end
#protocol DetailViewControllerDelegate<NSObject>
- (void)additem:(NSString *)Name MOBILE:(NSString *)Mobile;
#end
And DetailViewController.m-
#import "DetailViewController.h"
#interface DetailViewController ()
#end
#implementation DetailViewController
- (void)viewDidLoad {
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
- (IBAction)Save:(id)sender {
[self.delegate additem:self.nameTextField.text MOBILE:self.mobileTextField.text];
[self.navigationController popToRootViewControllerAnimated:YES];
}
#end
Now, if you put a break point inside your action method, you will see, it is getting called.
You can see an extra line of code-
[self.navigationController popToRootViewControllerAnimated:YES];
-this is making sure that when you press the save button, it not only sends the data, but also returns to you TableView Controller to show your results.
Now, you need to make sure that your DetailViewController knows who is going to implement its delegate. So, in your ContactTableViewController, wherever, you are initialising your DetailViewController, you have to assign its delegate to self.
So, after a little tweaks, the ContactTableViewController.h class looks like-
#import <UIKit/UIKit.h>
#import "DetailViewController.h"
#interface ContactTableViewController : UITableViewController<DetailViewControllerDelegate>
#property(strong,nonatomic)NSString *contactName;
#property(strong,nonatomic)NSString *contactNo;
-(void)reloadtabledata;
#property(strong,nonatomic)NSMutableArray *contactNameArray; //need to be mutable array, so that the data can keep appending
#property(strong,nonatomic)NSMutableArray *contactMobileNoArray; //same as above
#end
Now, there are some small modifications in the file but, the comments should clarify the purpose.
So, the ContactTableViewController.m file looks like
#import "ContactTableViewController.h"
#interface ContactTableViewController ()
#end
#implementation ContactTableViewController
- (void)viewDidLoad {
[super viewDidLoad];
//Make sure you initialize the array before tryig to add any element
self.contactNameArray =[[NSMutableArray alloc]init];
self.contactMobileNoArray=[[NSMutableArray alloc]init];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#pragma mark-
#pragma mark- TableView Datasource methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.contactNameArray count]; //you need to set the row count as the same as the array elements
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellreuse" forIndexPath:indexPath];
cell.textLabel.text=[self.contactNameArray objectAtIndex:indexPath.row];
cell.detailTextLabel.text=[self.contactMobileNoArray objectAtIndex:indexPath.row];
return cell;
}
-(void)reloadtabledata
{
[self.tableView reloadData];
}
#pragma mark- Segue method
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
[segue.destinationViewController setTitle:#"Add Details"];
DetailViewController *vc = [segue destinationViewController];
vc.delegate=self; // By this, you just told your TableViewController that it is responsible for the implementation of the DetailViewController's delegate
}
#pragma mark- DetailViewController's Delegate method
- (void)additem:(NSString *)Name MOBILE:(NSString *)Mobile
{
self.contactName=Name;
self.contactNo=Mobile;
[self.contactNameArray addObject:self.contactName]; //added the new entry
[self.contactMobileNoArray addObject:self.contactNo]; //added the new entry
[self.tableView reloadData]; //reload the table right after you updated the arrays
}
#end
This should help you with all your queries. If there is a change in the ContactTableViewController.m file, I added one or more comments. I tried to run the app and this is working properly.
Hey Just add this line in your view did load method of Contacttableviewcontroller.
DetailViewController *detailVc=[DetailViewController alloc]init];
detailVc.delegate =self;
Try this one
detailviewcontrollerdelegate
#import <Foundation/Foundation.h>
#protocol detailviewcontrollerdelegate<NSObject>
- (void)additem:(NSString *)Name MOBILE:(NSString *)Mobile;
#end
Detailviewcontroller.h
#import <UIKit/UIKit.h>
#import "detailviewcontrollerdelegate.h"
#interface DetaiViewController : UIViewController{
id< detailviewcontrollerdelegate > delegate;
}
#property (nonatomic, assign) id< detailviewcontrollerdelegate > delegate;
#property (weak, nonatomic) IBOutlet UITextField *nametextfield;
#property (weak, nonatomic) IBOutlet UITextField *mobiletextfield;
- (IBAction)Save:(id)sender;
and other as u have done make it same
**Detailviewcontroller.m**
- (IBAction)Save:(id)sender {
[self.delegate additem:self.nametextfield.text MOBILE:self.mobiletextfield.text];
}

iOS: how class notify something to UI view?

Starting point
I have a class, say A, used by an UI view.
A has a delegate that should notify UI view and this one should be write something on screen.
Question
What is the best approach to achieve this feature?
Seems something like observer-observable pattern
Code
---A.h
#interface A : NSObject
#end
---A.m
#implementation A
-(void)fooDelegate:(FooType *)sender {
/* Here I need to notify UI (that change notificationArea.text) */
}
---UIView.h
#interface UIView : UIViewController
#property(strong, nonatomic, retain) A* a;
#property(strong, nonatomic) IBOutlet UITextField *notificationArea;
#end
Based on the comments, I guess just code is what you're looking for...
Create your delegate protocol:
#protocol ADelegate;
#interface A : NSObject
#property (nonatomic, weak) id <ADelegate> delegate;
#end
#protocol ADelegate <NSObject>
#optional
-(void)fooDelegate:(A *)a;
#end
Notify your delegate:
#implementation A
-(void)fooDelegate:(FooType *)sender {
if ([[self delegate] respondsToSelector:#selector(fooDelegate:)]) {
[[self delegate] fooDelegate:self];
}
}
#end
Conform to the delegate protocol:
#import "A.h"
#import "MyView.h"
#interface MyView <ADelegate>
#end
#implementation MyView
-(void)fooDelegate:(A *)a {
// update text field here
}
#end
Finally, whenever you create an instance of A, set the delegate (where self in this example is an instance of MyView:
A *a = [[A alloc] init];
[a setDelegate:self];

Xcode - How to call method from another class

my first class .h :
#interface CollectionViewController : UICollectionViewController <..>
#property (strong, nonatomic) IBOutlet UICollectionView *collectionView;
-(void)refreshView;
#end
my first class .m
#implementation CollectionViewController
-(void)refreshView
{
[self.collectionView reloadData];
}
#end
i need to call this method from my second class
my second class .h
#interface CollectionViewCell : UICollectionViewCell
- (IBAction)buttonAction:(id)sender;
#end
my second class .m
#implementation CollectionViewCell
- (IBAction)myButtonAction:(id)sender {
//i need to call the method "refreshView" here
}
#end
I tried to edit the method refreshView from private to public but it's not compatible with "[self.collectionView reloadData];"
Thanks for help.
It's not a good idea to have your cell "know about" its collection view.
Use delegation instead...
CollectionViewCell.h
#protocol CollectionViewCellDelegate <NSObject>
- (void)refreshButtonPressedForCell:(CollectionViewCell *)cell;
#end
#interface CollectionViewCell : UICollectionViewCell
#property (nonatomic, weak) id<CollectionViewCellDelegate> delegate;
#end
CollectionViewController.m
#interface CollectionViewController : UICollectionViewController <CollectionViewCellDelegate>
#end
#implementation CollectionViewController
- (void)refreshButtonPressedForCell:(CollectionViewCell *)cell {
[self.collectionView reloadData];
}
#end
Don't forget to set the delegate property on each of your cells!

Delegate method not executing

I'm really having a tough time figuring out why one of my delegate methods performs perfectly, but another won't. Here is the relevant code for the delegate that isn't working:
SideBarController.h
#import <UIKit/UIKit.h>
#import "Report.h"
#protocol ReportSelectViewControllerDelegate <NSObject>
#optional
- (void) viewSelectMonitoredArea:(Report *)report;
#end
#interface SidebarController : UIViewController <UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, weak) id <ReportSelectViewControllerDelegate> delegate;
#property (nonatomic, weak) IBOutlet UITableView *tableView;
#property (nonatomic, weak) Report *selectedReport;
#end
SideBarController.m
#import "SidebarController.h"
#interface SidebarController ()
#end
#implementation SidebarController
#synthesize tableView = _tableView;
#synthesize delegate;
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
NSMutableArray *sectionArray = [self.tableViewItems objectAtIndex:indexPath.section];
NSDictionary* item = sectionArray[indexPath.row];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:item[#"title"] forKey:#"CurrentReportTitle"];
self.selectedReport = [Report where:#{#"reportTitle": item[#"title"]}].lastObject;
[self.delegate viewSelectMonitoredArea:self.selectedReport];
[tableView deselectRowAtIndexPath:indexPath animated:YES];
}
DetailReportViewController.h
#import <UIKit/UIKit.h>
#import "BDBSplitViewController.h"
#import "SidebarController.h"
#interface DetailReportViewController : BDBDetailViewController <UISplitViewControllerDelegate, ReportSelectViewControllerDelegate >
#end
DetailReportViewController.m
#import "DetailReportViewController.h"
#interface DetailReportViewController ()
#end
#implementation DetailReportViewController
- (void)viewDidLoad
{
[super viewDidLoad];
SidebarController *sideBarController = [[SidebarController alloc] init];
sideBarController.delegate = self;
}
- (void) viewSelectMonitoredArea:(Report *)report {
NSLog(#"viewSelectMonitoredArea was called");
}
Another delegate written exactly the same way from another controller to the DetailReportViewController works just fine. When I put a breakpoint right after the delegate is called, I notice that the delegate has a nil value. Any help would be greatly appreciated.
EDIT:
Sorry, I forgot to put in sideBarController.delegate = self in the DetailReportViewController.h example. It is in the original code.
The DetailReportViewController class needs to get a reference to the "SideBarController" instance and then set itself as the delegate. In DetailReportViewController:
// This needs to be in the DetailReportViewController class
// Assume we have a reference to the SideBarController in the DetailReportViewController class called sideBarControllerInstance
sideBarControllerInstance.delegate = self;
The solution spurred on by Michael Dautermann was to put
DetailReportViewController *detailReport = [[DetailReportViewController alloc] init];
self.delegate = detailReport;
right before
[self.delegate createSelectMonitoredArea:self.selectedReport];
Thanks!

Cant call delegate method from my protocol class

I have a protocol in one class:
#protocol DataStorageManager
- (void) saveFile;
#end
#interface DataManager : NSObject
{
id <DataStorageManager> delegate;
}
#property (nonatomic, assign) id<DataStorageManager> delegate;
//methods
#end
and its implementation:
#implementation DataManager
#synthesize delegate;
#end
and I have another class which is the adapter between the first and the third one:
#import "DataManager.h"
#import "DataPlistManager.h"
#interface DataAdapter : NSObject <DataStorageManager>
#property (nonatomic,strong) DataPlistManager *plistManager;
- (void) saveFile;
#end
and its implementation
#import "DataAdapter.h"
#implementation DataAdapter
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
return self;
}
- (void) saveFile
{
[self.plistManager savePlist];
}
#end
So when I in first method try to call my delegate method like this
[delegate saveFile];
Nothing happened. I don't understand what's wrong with the realization - it's a simple adapter pattern realization. So I need to use the delegate which will call the methods from the third class. Any help?
You are not setting the delegate property. You need to do this,
-(id) initWithDataPlistManager:(DataPlistManager *) manager
{
self = [super init];
self.plistManager = manager;
self.plistManager.delegate = self;
return self;
}
Also, in DataManager class remove the ivar declaration, just declaring property is sufficient, the ivar gets automatically created. Call the delegate method as below,
if([self.delegate respondsToSelector:#selector(saveFile)] {
[self.delegate saveFile];
}
Hope that helps!
In your case you forget to set your protocol delegate and also need to call protocol method
by self.delegate....
I just Give Basic Idea for how to Create Protocol
Also Read This Question
#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);
}

Resources