_delegate respondsToSelector:selector is not calling the method - ios

I have one class and one view controller. class has _delegate respondsToSelector:selector. But it is not calling the method(selector). After viewing my code below, would you please tell what am I doing wrong. FYI, This code worked before, but suddenly stopped working.
MyClass.h:
#protocol MyClassDelegate <NSObject>
#optional
-(void) receivedEvent:(TripEvent *) event;
#end
#interface MyClass : NSObject<MyClassEngine>
#property(assign) id<MyClassDelegate> delegate;
#property BOOL delegateOnMainThread;
-(id) initWithDelegate:(id<UbiTripRecorderDelegate>) tripDelegate
onMainThread:(BOOL) onMainThread;
- (void) dispatchDelegate:(SEL)selector
withObject:(id)obj;
MyClass.m contains the following code:
#import "MyClass.h"
#implementation MyClass
....
....
-(void) startPlaying {
[self dispatchDelegate:#selector(receivedEvent:) withObject:newEvent];
}
- (void) dispatchDelegate:(SEL)selector withObject:(id)obj {
#try {
if(_delegate && [_delegate respondsToSelector:selector]) {
NSLog(#"I can't come to this point");
}
}
}
I've also added the following code in my view controller (MyViewController.h):
#interface MyViewController : BaseViewController<MyClassDelegate>
And finally implemented the method in MyViewcontroller.m :
-(void) receivedEvent : (TripEvent *) event {
NSLog(#"I'm called");
}
The problem is that the if(_delegate && [_delegate respondsToSelector:selector]) - logic never return true. Can anybody please check the code and let me know, if anything is wrong with my code?

Make sure your _delegate is not nil, otherwise the if statement is never true.
Also you can simplify
if(_delegate && [_delegate respondsToSelector:selector])
to
if([_delegate respondsToSelector:selector])
because message send to nil always return 0 or NO. In this case [_delegate respondsToSelector:selector] will return NO if _delegate is nil
Also, you did not declare a method in header will not cause any runtime difference. It may have compiler warning/error if such method not found.

Related

Calling a method from other class

I have 2 classes named as:
InputFunctionView
BaseTemplateView
I created a method cancelStickerPreviewButtonPressed inside InputFunctionView class that I want to call it from BaseTemplateView class.
Here is my code:
InputFunctionView.h
#import <...>
#class InputFunctionView;
#protocol InputFunctionViewDelegate <NSObject>
...
#end
#interface InputFunctionView : UIView <...> {
}
- (void)cancelStickerPreviewButtonPressed:(id)sender;
#end
InputFunctionView.m
- (void)cancelStickerPreviewButtonPressed:(id)sender {
// This part doesn't work when called from other class. Why?
NSLog(#"cancel sticker preview");
[self.previewCancelButton removeFromSuperview];
[_stickerPreviewView removeFromSuperview];
}
BaseTemplateView.h
#import <...>
#interface BaseTemplateView : UIViewController
#end
BaseTemplateView.m
#import "InputFunctionView.h"
- (void) MethodA {
InputFunctionView *IFV = [[InputFunctionView alloc]init];
[IFV cancelStickerPreviewButtonPressed:nil];
}
My question is why in InputFunctionView.m method cancelStickerPreviewButtonPressed this below part doesn't work? previewCancelButton and stickerPreviewView are supposed to be removed from its superview but no. What am I missing?
// This part doesn't work when called from other class. Why?
NSLog(#"cancel sticker preview");
[self.previewCancelButton removeFromSuperview];
[_stickerPreviewView removeFromSuperview];
Might be help you using Class method
In InputFunctionView.h
+(void)yourMethod;
In InputFunctionView.m
+(void)yourMethod
{
NSLog(#"Your method called");
}
In BaseTemplateView.h
- (void) MethodA { // Need to import InputFunctionView.h
[InputFunctionView yourMethod];
}
Happy coding...

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.

Delegate Pattern ios

I've been following this example to help me build a delegate but unfortunately I've missed something so it is not working for me. How do I set up a simple delegate to communicate between two view controllers?
My code looks like this:
// HintsViewController.h
#import <UIKit/UIKit.h>
#protocol HintDelegateProtocol;
#interface HintsViewController : UIViewController
#property (weak, nonatomic) id<HintDelegateProtocol> hintDelegate;
-(IBAction)showFirstLetter:(id)sender
-(IBAction)showHint:(id)sender;
-(IBAction)showAnswer:(id)sender;
#end
#protocol HintDelegateProtocol <NSObject>
-(void)HintsViewController:(HintsViewController*)hintsViewController
showFirstLetter:(NSString*)firstLetter;
-(void)HintsViewController:(HintsViewController*)hintsViewController
showHint:(NSString*)hint;
-(void)HintsViewController:(HintsViewController*)hintsViewController
showAnswer:(NSString*)answer;
#end
//
// HintsViewController.m
#import "HintsViewController.h"
#implementation HintsViewController
#pragma mark -
#pragma mark IBActions
/* As per a suggestion below I changed the code here /*
- (IBAction)showHint:(id)sender
{
[self.hintDelegate HintsViewController:self showHint:#"Hint"];
}
- (IBAction)showFirstLetter:(id)sender
{
[self.hintDelegate HintsViewController:self showFirstLetter:#"FirstLetter"];
}
- (IBAction)showAnswer:(id)sender
{
[self.hintDelegate HintsViewController:self showAnswer:#"Answer"];
}
#end
And then in the a Controller class I have the following:
//
// GameLogicController.h
#import "HintsViewController.h"
#interface GameLogicController : NSObject < HintDelegateProtocol>
#end
And in the implementation I have the following:
// GameLogicController.m
-(void) nextRiddle
{
HintsViewController *hintsViewController = [[HintsViewController alloc] init];
hintsViewController.hintDelegate = self;
}
#pragma mark -
#pragma mark HintsFunctionality
-(void)HintsViewController:(HintsViewController*)hintsViewController
showFirstLetter:(NSString*)firstLetter
{
NSLog(#"Show First Letter called");
}
-(void)HintsViewController:(HintsViewController*)hintsViewController
showHint:(NSString*)hint
{
NSLog(#"show Hint called");
}
-(void)HintsViewController:(HintsViewController*)hintsViewController
showAnswer:(NSString*)answer
{
NSLog(#"Show answer called");
}
Using breakpoints I can see that the IBActions in the HintsViewController are being called, but putting a breakpoint in any of the delegate methods in the gameLogicController are never hit. So I have missed an important step in setting up the connection between the GameLogicController and the HintsViewController. Can anyone help me spot it?
Say you have two files: one is your ViewController, and other is your ConnectionManager Class.
Declare protocol and its methods in your ConnectionManager class, and define your protocol methods in the ViewController class. By setting the delegate of your ConnectionManager class in ViewController Class, you can call your Protocol method.
#protocol ConnManagerDelegate<NSObject>
- (void)didReceiveData:(NSDictionary *)data;
- (void)didFailWithError:(NSError*)error;
#end
#interface ConnectionManager : NSObject<NSURLConnectionDelegate>
#property(nonatomic,assign)id< ConnManagerDelegate > delegate;
And elseswhere in the same file .m, when your response comes just call
[Self.delegate didReceiveData:mDict];
In the ViewController file after you alloc init ConnectionManager class, set its delegate to self and define the protocol methods. It is these methods you will have your response from ConnectionManager class.
This is all Protocol Delegation pattern

ios nsCoding set but not calling encodeWithCoder

I am trying to use NSCoding to save and recover application state. I haven't used it before.
In my app, the protocol methods encodeWithCoder and initWithCoder are never being called. I have prepared a simple test case with the same problem so hopefully somebody can tell me what I am doing wrong.
Here is my CodingTest.h file:
#import <Foundation/Foundation.h>
#interface CodingTest : NSObject <NSCoding>
- (void) saveData;
- (void) loadData;
- (id) init: (int) testValue;
#end
Here is CodingTest.m
#import "CodingTest.h"
#interface CodingTest()
#property int testInt;
#end
#implementation CodingTest
- (id) init: (int) testValue
{
_testInt = testValue;
return self;
}
-(void) loadData
{
CodingTest *newTestClass = [NSKeyedUnarchiver unarchiveObjectWithFile:#"testfile"];
}
-(void) saveData
{
[NSKeyedArchiver archiveRootObject:self toFile:#"testfile"];
}
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeInt:_testInt forKey:#"intValue"];
}
- (id)initWithCoder:(NSCoder *)decoder {
int oldInt = [decoder decodeIntForKey:#"intValue"];
return [self init:oldInt];
}
#end
I call it as follows:
CodingTest *testCase = [[CodingTest alloc] init:27];
[testCase saveData ];
[testCase loadData];
init, saveData and loadData are all being called. But encodeWithEncoder and initWithCoder are never called. What am I doing wrong?
The problem is that "testfile" on its own is not a valid filename. If this is changed to "tmp/testfile" it works fine.
Interestingly, if you get the file name wrong on encode, it won't call the decode function, even though the decode call doesn't specify the file name.

delegate deallocated during the operation

I'm looking for a solution that solves the following problem:
I have a NSOperation which download the image in the background:
#protocol CoreImageDownloadingOperationDelegate <NSObject>
#required
-(void) handleResponse:(UIImage*) response;
-(void) handleException:(MobileServiceException*) exception;
#end
#interface CoreImageDownloadingOperation : NSOperation{
}
-(id) initWithDelegate:(id<CoreImageDownloadingOperationDelegate>)del andImageID: (NSString *) image;
#property (nonatomic, assign) id <CoreImageDownloadingOperationDelegate> delegate;
When it's finish the downloading, calling the delegate method, to set the image to the imageView:
pragma mark - overridden from NSOperation
- (void) main {
if (self.isCancelled)
return;
#autoreleasepool {
#try {
UIImage* image = [[CoreEnvironment sharedInstance] getImageFromServer: [imageID stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
if (self.isCancelled)
return;
if(delegate){
[delegate handleResponse:image];
}
else
NSLog(#"CachedImageView already deallocated");
}#catch (NSException *exception) {
TestLog(#"%#", exception.reason);
if (self.isCancelled)
return;
if(delegate && [exception isKindOfClass:[MobileServiceException class]])
[delegate handleException:(MobileServiceException*)exception];
}
}
}
The problem is: when I go to another page while the image is downloading, the cachedImageView is deallocated, but when the imageDownloadingOperation finishes downloading, the delegate is not nil, and it's trying to handleResponse... And of course I get message sent to deallocated...
I alloc init the operation like this in the CachedImageView:
CoreImageDownloadingOperation* imageDownloadingOperation = [[CoreImageDownloadingOperation alloc] initWithDelegate:self andImageID:imageKey];
or:
-[CachedImageView isKindOfClass:]: message sent to deallocated instance 0x18868550
The problem is: when I go to another page while the image is
downloading, the cachedImageView is deallocated
The usual way to deal with this is to remove itself as a delegate in the dealloc of CachedImageView. Like
// in CachedImageView
- (void)dealloc {
// CachedImageView keeps a reference to the operation
// called imageDownloadingOperation
imageDownloadingOperation.delegate = nil;
[super dealloc];
}
Where is your protocol declaration? I'd expect to see this:
#protocol CoreImageDownloadingOperationDelegate <NSObject>
- (void) handleResponse:(UIImage *) image;
#end
#interface CoreImageDownloadingOperation : NSOperation{
}
-(id) initWithDelegate:(id<CoreImageDownloadingOperationDelegate>)del andImageID: (NSString *) image;
#property (nonatomic, assign) id <CoreImageDownloadingOperationDelegate> delegate;
You are getting the warning/crash because it can't find the responder handleResponse:
Also when invoking the delegate your better off doing:
if ([self.delegate respondsToSelector:#selector(handleResponse:)])
[self.delegate handleResponse:image];
You don't need to check if (self.delegate && [self.delegate responds .... as it will return nil if the delegate is nil && if the selector is not implemented.
EDIT *
Where you create:
CoreImageDownloadingOperation* imageDownloadingOperation = [[CoreImageDownloadingOperation alloc] initWithDelegate:self andImageID:imageKey];
I suspect this is being released, turn this into a property of the class it's in. Then try again (make sure to release it when you're done though) i.e
In your .h
#property (nonatomic, retain) CoreImageDownloadingOperation* imageDownloadingOperation;
Then initialise with:
if (!self.imageDownloadingOperation)
self.imageDownloadingOperation = [[CoreImageDownloadingOperation alloc] initWithDelegate:self andImageID:imageKey];
A better way of writing the code is :
if([self.delegate respondsToSelector:#selector(handleResponse:)){
[self.delegate handleResponse:image];
}
This will avoid your crash.
I've solved the problem, I used CW0007007 solution and my own solution. So I turned my operation into a retained property:
#property (nonatomic, retain) CoreImageDownloadingOperation* imageDownloadingOperation;
after this I checked if the operation is still alive
if (!imageDownloadingOperation)
imageDownloadingOperation = [[CoreImageDownloadingOperation alloc] initWithDelegate:self andImageID:imageKey];
then added to the operation queue.
In the dealloc set the delegate to nil ( ofc only if the operation is alive ), and release it:
if (imageDownloadingOperation) {
imageDownloadingOperation.delegate = nil;
[imageDownloadingOperation release];
}
in the operation: ( and now if the imageView deallocated, its delegate will be nil, and won't crash anytime )
if (delegate)
if ([delegate respondsToSelector:#selector(handleResponse:)])
[delegate handleResponse:image];

Resources