Custom delegate issue - ios

I'm working with a custom delegate and protocol functionality.
I implemented my class like follows:
#protocol MyDelegate <NSObject>
#required
- (void)update;
#end
#interface MyHandlerClass : NSObject
{
id <MyDelegate>delegate;
}
#property (nonatomic, weak) id <MyDelegate>delegate;
#end
My implementation class looks like:
#implementation MyHandlerClass
#synthesize delegate = _delegate;
- (void)updateRequired: (id)sender
{
if(delegate)
{
[delegate update];
}
}
#end
And from another class I'm setting it like:
[sharedManager setDelegate:self];
But when the updateRequired is triggered it is showing as nil.
Then I added a setter method like:
- (void)setDelegate:(id<MyDelegate>)aDelegate
{
delegate = aDelegate;
}
Everything works fine !!!
Then I changed the updateRequired method (without custom setter) like:
- (void)updateRequired: (id)sender
{
if(_delegate)
{
[_delegate update];
}
}
It is also working fine !!!
I couldn't find why it is not worked for the first case and why it is worked for the other two cases ?
Please help me to find the issue, Thanks in advance

When you use
if(delegate)
You are pointing to the instance variable "delegate".
However, when you use
[sharedManager setDelegate:self]
This is setting the instance variable "_delegate" to "self".
Try this:
if (self.delegate) {
[self.delegate update];
}

You have inadvertently declared one ivar called delegate
id <MyDelegate>delegate;
and another ivar called _delegate
#synthesize delegate = _delegate;
Some suggestions...
don't declare the iVar separately from your #property declaration
don't #synthesize, since XCode 4.4 you don't have to. The compiler will autosynthesize and autocreate an iVar with leading underscore
always refer to you ivar via it's property, inside and outside of your class. Only exceptions are in init, dealloc and inside custom setters and getters.
So this is how your code should look
#protocol MyDelegate <NSObject>
#required
- (void)update;
#end
#interface MyHandlerClass : NSObject
#property (nonatomic, weak) id <MyDelegate>delegate;
#end
#implementation MyHandlerClass
- (void)updateRequired: (id)sender
{
if(self.delegate)
{
[self.delegate update];
}
}
#end

To access your delegate property in the updateRequired method, you can do it by either using the private variable _delegate or by using self.delegate. Because when you synthesize using delegate = _delegate, setters and getters are automatically created.
This line tells the compiler to create a setter and getter for delegate, and that they should use the ivar called _delegate. Without the = _delegate part, the compiler would assume that the property and ivar have the same name.

Related

custom deleget not responding ToSelector

Following is my code, there is no error but selector is not responding.
Code in ExampleTableviewSubProductDetail.h
#protocol EnterAmountDelegate <NSObject>
-(void)titlechange:(NSInteger)amount;
#end
#class ASIFormDataRequest;
#interface ExampleTableviewSubProductDetail : UIViewController<UIScrollViewDelegate>
{
}
#property (nonatomic, strong) id <EnterAmountDelegate>delegate;
Code in ExampleTableviewSubProductDetail.m
#implementation ExampleTableviewSubProductDetail
#synthesize delegate;
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if([delegate respondsToSelector:#selector(titlechange:)])
{
//send the delegate function with the amount entered by the user
[delegate titlechange:20];
}
code in HostProductdetailViewController.h
#import "ViewPagerController.h"
#import "ExampleTableviewSubProductDetail.h"
#interface HostProductdetailViewController : ViewPagerController <ViewPagerDataSource, ViewPagerDelegate, EnterAmountDelegate>
{
}
code in HostProductdetailViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
self.dataSource = self;
self.delegate = self;
}
-(void)titlechange:(NSInteger)amount
{
NSLog(#"sdfsf");
}
In the viewwillapper following Line always return false
if([delegate respondsToSelector:#selector(titlechange:)])
Please let me know if i am missing anything.
Thanks
When pushing from HostProductdetailViewController to ExampleTableviewSubProductDetail you need to set the exampleTableviewSubProductDetail.delegate = self
As I see some other potentially dangerous things in your code try checking this example. It consists of 2 simple classes which are connected via delegate. Watch out for strong references on delegates as this code of yours will produce a retain cycle and cause a memory leak.
Protocol:
// defining a custom protocol
#protocol PingProtocol <NSObject>
- (void)didPing;
#end
Ping class:
//
// This class will be able to send notifications via delegate for the protocol PingProtocol
// Any object that implements PingProtocol will be able to assign itself to the delegate property and will be notified to all protocol methods
//
#interface PingClass : NSObject
// The listener object that implements PingProtocol
// Note this should be weak or there will a retain cycle
#property (nonatomic, weak) id<PingProtocol> delegate;
#end
#implementation PingClass
// Some event that happens will check if the delegate actually implements this method and call it.
// The respondsToSelector is not necessary in this case since the method is not optional though.
- (void)onEvent:(id)sender
{
if([self.delegate respondsToSelector:#selector(didPing)])
{
[self.delegate didPing];
}
}
// Will create a timer which will call onEvent: every second.
// Note there should be some way to invalidate the timer as this will cause a memory leak for the PingClass
- (void)startPing
{
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(onEvent:) userInfo:nil repeats:YES];
}
#end
Listener:
//
// This class will listen to PingProtocol methods.
// It will need to implement all non-optional methods defined by PingProtocol
//
#interface ListenerClass : NSObject<PingProtocol>
#property (nonatomic, strong) PingClass *someClass;
#end
#implementation ListenerClass
// will create a PingClass object and asign itself as a delegate to start listening to delegate methods
- (void)startListening
{
self.someClass = [[PingClass alloc] init];
self.someClass.delegate = self;
[self.someClass startPing];
}
// A protocol method
- (void)didPing
{
NSLog(#"Ping");
}
#end
Most likely you are missing self:
if([self.delegate respondsToSelector:#selector(titlechange:)])
You need to watch out for these things. The delegate in your case is closer to a function pointer then an actual object. You might also be able access it via _delegate as well.

Setting BOOL to "YES" in custom delegate

I've make a delegate so my two different view controllers can communicate and I'm stuck trying to set a BOOL to YES in my child view controller.
childViewController.h
#protocol pageTwoViewControllerDelegate;
#interface pageTwoViewController : UIViewController {
UIButton *takePhotoTransition;
}
#property (nonatomic, weak) id<pageTwoViewControllerDelegate> delegate;
#end
#protocol pageTwoViewControllerDelegate <NSObject>
- (BOOL)didPushTakePhoto;
#end
childViewController.m
...
- (IBAction)takePhotoTransition:(id)sender {
id<pageTwoViewControllerDelegate> strongDelegate = self.delegate;
if ([strongDelegate respondsToSelector:#selector(didPushTakePhoto)]) {
strongDelegate.didPushTakePhoto = YES; // ERROR: No setter method for 'setDidPushTakePhoto:' for assignment property
}
NSLog(#"Button push recieved");
}
How can I get past this error and set my BOOL to YES when my button is pushed?
The protocol is just telling everyone that knows about your class through the protocol, that the property anObject will be there. Protocols are not real, they have no variables or methods themselves
Try to modify your code to be like this, you are setting a non existence variable or property.
you have to implement new Class instead of id
your protocol will look like
#protocol pageTwoViewControllerDelegate <NSObject>
- (void)setdidPushTakePhoto:(BOOL)aBOOL;
- (BOOL)didPushTakePhoto;
#end
and your class.h will contain
#property (nonatomic, getter=get_didPushTakePhoto) BOOL didPushTakePhoto;
and your class.m will contain implementation
-(BOOL)didPushTakePhoto
{
return _didPushTakePhoto;
}
- (void)setdidPushTakePhoto:(BOOL)aBOOL{
_didPushTakePhoto=aBool;
}
You are getting confused between a method and a property.
The definition of your protocol "pageTwoViewControllerDelegate", says it should implement a method with name "didPushTakePhoto" which returns a BOOL value.
What you are trying to do is entirely different. You are trying to set a non-existent property. Whenever you are accessing something followed by a dot ".", that should be a property of the class to which that object belongs. The protocol you defined does not talk anything about the property.
So inside the if condition, you should be calling the method "didPushTakePhoto" on your delegate object, like below.
[strongDelegate performSelector:#selector(didPushTakePhoto)];
If you know for sure that your delegate implementations do have the protocol method implemented, then since you already cast self.delegate to strongDelegate which is declared as id, you don't need the if condition. You could directly call the method like below.
[strongDelegate didPushTakePhoto];
Hope this helps
Have you assigned the delegate of your ChildViewController belongs to ParentViewController?
Try this:
ParentChildViewController.m
#import "ChildViewController.h"
#interface ParentViewController () <ChildDelegate>
...
-(IBAction)btnClicked:(id)sender
{
ChildViewController *ctrl = [[ChildViewController alloc] init];
ctrl._delegate = self;
// do present childViewController or similar action here
}
- (void)didPushTakePhoto: (BOOL)result{
NSLog(#"result: %d",result);
}
ChildViewController.h
#protocol ChildDelegate
- (void)didPushTakePhoto: (BOOL)result;
#end
#interface pageTwoViewController : UIViewController {
UIButton *takePhotoTransition;
}
#property (assign, nonatomic) id _delegate;
#end
ChildViewController.m
...
- (IBAction)takePhotoTransition:(id)sender {
if ([self._delegate respondsToSelector:#selector(didPushTakePhoto:)]) {
[self._delegate didPushTakePhoto:YES];
// do dismiss here
}
}

ios Objective C delegate methods

This is my first day of Objective C so I apologise for the lack of knowledge.
I need to import an existing SKD into an App and I done it successfully. Now I need to create the delegate methods and I don't understand how can I do it.
This is the structure of the header file included from the SDK (SDKManager.h):
#protocol SDKManagerDelegate;
#interface SDKManager : NSObject
#property (nonatomic, weak) id<SDKDelegate> delegate;
+(void)initialize:(NSString*)appId withKEY:(NSString*)key;
+(void)setHandler:(id)delegate;
#end
#protocol SDKManagerDelegate <NSObject>
#required
-(void)appDidReceiveTokens:(NSDictionary*)items withResponse:(NSDictionary*)response;
#end
So, from my FirstViewController.m I was able to import the header and call two methods:
#import "FirstViewController.h"
#import "SDKManager.h"
#interface FirstViewController ()
#end
#implementation FirstViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[SDKManager setHandler:[UIApplication sharedApplication].delegate];
[SDKManager initialize:#"AppId"withKEY:#"1234"];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
but I have noticed that I am not able to call the other methods (i.e. appDidReceiveTokens).
Actually the instructions require to create those methods but I have no idea where.
Any help is really appreciated.
Thank you
You do not call delegate methods directly in the files in which you are implementing the delegate methods. Review Apples documentation on the concept of Delegation.
To implement this properly you would adopt the delegate in your class, then implement the delegate methods that are #required and/or #optional.
You've correctly created the delegate protocol and a property to store the SDKManager's delegate.
Your setHandler: and initialize:withKEY: methods are class methods, whereas the delegate property belongs to each instance of SDKManager. Without seeing your implementation file (.m) for SDKManager, it's hard to know why you've set it up this way. You may be attempting to follow a singleton pattern - if so, read up on it, e.g. here.
The reason for that is you have class methods which sets the calls setHandler method and the delegate is property, so where do you assign the delegate and when and how do you call the delegate. I hope you understand what a class and instance is. So, you cannot call the delegate until you create instance of your object.
You have two different class methods which is used to set some attributes to the class, would it make sense to have them as property.
More generic and better way to do this would be like this,
#protocol SDKManagerDelegate <NSObject>
#required
-(void)appDidReceiveTokens:(NSDictionary*)items
withResponse:(NSDictionary*)response;
#end
#protocol SDKManagerDelegate;
#interface SDKManager : NSObject
- (instancetype)initWithAppId:(NSString *)appId
key:(NSString *)key
delegate:(id<SDKManagerDelegate>)delegate;
#end
#interface SDKManager ()
#property (nonatomic, copy, readonly) NSString *appId;
#property (nonatomic, copy, readonly) NSString *key;
#property (nonatomic, weak, readonly) id<SDKManagerDelegate> delegate;
#end
#implementation SDKManager
- (instancetype)initWithAppId:(NSString *)appId
key:(NSString *)key
delegate:(id<SDKManagerDelegate>)delegate
{
if (self = [super init]) {
_appId = [appId copy];
_key = [key copy];
_delegate = delegate;
}
return self;
}
- (void)doSomeNetworkRequestHere
{
[self fetchTokenFromServer:^(NSDictionary *tokens, NSDictionary *response){
[self.delegate appDidReceiveTokens:tokens
withResponse:response];
}];
}
- (void)fetchTokenFromServer:(void(^)(NSDictionary *tokens, NSDictionary *response))completion
{
}
#end

add implementation UIWebView(CustomScroll)

I'm trying to add this to my code
#implementation UIWebView(CustomScroll)
- (void) scrollViewDidScroll:(UIScrollView *)scrollView{
[self.delegate scrollViewDidScroll: scrollView];
}
#end
But getting "No known instance method for selector 'scrollViewDidScroll:'"
What am I missing here?
The UIWebViewDelegate protocol does not declare a method scrollViewDidScroll:. Hence, this is why you're getting the bad access error.
I'd recommend that you subclass UIWebView instead of trying to creating a category on it (yes, the docs recommend against subclassing... just don't override any of the methods it has, and it's safe).
On your subclass, you can either create a new protocol or simply overwrite the delegate property to also require that it conforms to `UIScrollViewDelegate (the later is shown below):
In Example:
// MyWebView.h
#import <UIKit/UIKit.h>
#interface MyWebView : UIWebView
#property (nonatomic, assign) id<UIWebViewDelegate, UIScrollViewDelegate> delegate;
#end
// MyWebView.m
#import "MyWebView.h"
#implementation MyWebView
-(void)scrollViewDidScroll:(UIScrollView *)scrollView
{
/* As scrollViewDidScroll: is optional, you should check if the super class
responds to this method (it doesn't appear to now, but this may change in future) */
if ([[self superclass] instancesRespondToSelector:#selector(scrollViewDidScroll:)])
{
[super scrollViewDidScroll:scrollView];
}
/* Likewise, you should check if your own delegate responds to this selector */
if ([self.delegate respondsToSelector:#selector(scrollViewDidScroll:)])
{
[self.delegate scrollViewDidScroll:scrollView];
}
}
#end

iOS - How to implement self created delegate in ios6

i have created a delegate for my project the code of my main view is
VedantViewController.h
#protocol VedantDelegate;
#interface VedantViewController : UIViewController
{
id <VedantDelegate> delegate;
}
//some other outlets
#property(nonatomic, assign) id <VedantDelegate> delegate;
#protocol VedantDelegate <NSObject>
- (void)display:(NSString *)JSONResponse;
#end
VedantViewController.m
#synthesize delegate;
[delegate display:jsonResponse];
SecondViewController.h
#interface SecondViewController : UIViewController<VedantDelegate>
- (void)display:(NSString *)JSONResponse;
SecondViewController.m
- (void)display:(NSString *)string
{
}
but this code is not working properly
when i debug the code using breakpoints the code reaches the
[delegate display:abc];
but it does not calls display function in SecondViewController.m file
i think my code is right but some mistake that i can't recognize
let me explain you the flow of my project this could be the problem
by default the VedantViewController view is launched
after that when the show button is click it calls the SecondViewController view in the view these is list button that calls the function in VedantViewController this function then calls the delegate method that is [delegate display:jsonResponse];
Thanks in Advance,
Arun.
The view controller which is confirming with the protocol, should have this line in the viewDidLoad or anywhere you are making the object of that viewController
Add this line in SecondViewController.m
VedantViewControllerObject.delegate = self;
#protocol VedantDelegate;
#interface VedantViewController : UIViewController{
id<VedantDelegate> delegate;
}
//some other outlets
#property(nonatomic,assign) id<VedantDelegate> delegate;
#protocol VedantDelegate <NSObject>
-(void)displayAccounts:(NSString *)JSONResponse;
-(void)display:(NSString *)JSONResponse;
#end
and also set delegate to object of VedantViewControllerObject class as self in SecondViewController class and the object of VedantViewControllerObject class should be initialized and allocated.
vedantViewControllerObject.delegate = self;
In your VedantViewController.h file you declared method as below
-(void)displayAccounts:(NSString *)JSONResponse;
But you are calling it [delegate display:jsonResponse];
You just try to call
[delegate displayAccounts:jsonResponse];
And in SecondViewController.m
(void)displayAccounts:(NSString *)string{
}
There are some issues in your code:
set the delegate in second view controller
vedViewObject.delegate = self;
You added displayAccounts method in delegate and calling display method, that can cause issues. If that methods are not implemented in the delegate class.
Add if condition like: if(delegate)[delegate displayAccounts:jsonResponse];

Resources