Subclass as delegate of superclass - ios

I have class ImageViewController. It has delegate:
#protocol ImageViewControllerDelegate
#optional
- (void)singleTapGestureRecognizer:(UITapGestureRecognizer *)gesture;
- (void)imageDidLoaded;
I also have class AttachmentViewController that subclass of ImageViewController. In that class I want to get event then image property in changed. So here is my code of it change:
- (void)setImage:(UIImage *)image
{
// * Assign image with animation
[UIView transitionWithView:self.imageView
duration:k_DURATION_imageAppearence
options:UIViewAnimationOptionTransitionCrossDissolve
animations: ^{
self.imageView.alpha = 1;
} completion:^(BOOL finished) {
if ([self respondsToSelector:#selector(imageDidLoaded)]) {
[self.delegate imageDidLoaded];
}
}];
But I can not use
if ([self.DELEGATE respondsToSelector:#selector(imageDidLoaded)])
Then I do it I have error:
No known instance method for selector 'respondsToSelector:'
Why? And how here I need to use this capabilities? Is my implementation ok? Or how can I get this notification?
I think that here will be ok to create clear methods in superclass and override it in subclass if it needs to implement is. Is it best way?

You should declare your protocol as #protocol ImageViewControllerDelegate <NSObject>
This says that any object that conforms to your protocol will also conform to the NSObject protocol that respondsToSelector: is declared in.

There's really not enough code here to understand what you're trying to do. Generally to setup a delegate you have a weak property on your class that represents the delegate, and a parent to that class's instance would set the delegate.
Here's some pseudo code:
#protocol SomeDelegateProtocol<NSObject>
- (void)someMethod:(id)someObject;
#end
#interface SomeClass:NSObject
#property (nonatomic, weak) id<SomeDelegateProtocol>delegate;
#end
#implementation SomeClass
- (void)someFunction {
if ([self.delegate respondsToSelector:#selector(someMethod:)]) {
// do code stuff
}
}
#end
///////////
#implementation SomeParentClass
- (void)someOtherFunction {
SomeClass *instance = [SomeClass new];
instance.delegate = self; // assuming self implements SomeDelegateProtocol, otherwise you get a warning
}
Hope this helps!

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
}
}

Delegate method not being called?

I have a view controller with a delegate method that should be called, but it doesn't?
NotifyingViewController.h
#protocol NotifyingViewControllerDelegate <NSObject>
#required
- (void)iWasAccepted;
#end
#interface NotifyingViewController : UIViewController
#property (nonatomic, weak) id<NotifyingViewControllerDelegate> delegate;
NotifyingViewController.m
-(void)someMethod{
[self.delegate iWasAccepted];
[self dismissViewControllerAnimated:YES completion:nil];
}
NotifiedViewController.h
#import "NotifyingViewController.h"
#interface NotifiedViewController : UIViewController <NotifyingViewControllerDelegate>
NotifiedViewController.m
-(void)iWasAccepted{
[self saveIntoDB];
NSLog(#"DELEGATE RAN");
}
For some reason, the controller that should be notified isn't. The Notifying controller does dismiss meaning the method that alerts the delegate IS run, but the delegate doesn't run the function because it doesn't NSLog. Any ideas why?
You can't just specify that an object conforms to a protocol. You must also assign that object as the delegate. When you alloc/init the instance of NotifyingViewController, set its delegate to self and you should be fine.
NotifyingViewController *notifyingInstance = [[NotifyingViewController alloc] init];
[notifyingInstance setDelegate:self];
It is important to both do this, and specify that the class conforms to the protocol, which you're already doing with this line.
#interface NotifiedViewController : UIViewController <NotifyingViewControllerDelegate>
Additionally, when calling delegate methods, it's good practice to wrap the function calls in respondsToSelector: checks.
if ([self.delegate respondsToSelector:#selector(iWasAccepted)]) {
[self.delegate iWasAccepted];
}

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

Custom delegate issue

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.

Resources