Search code examples
iosobjective-cdelegatesviewcontrolleruislider

Custom delegate does not working in iOS


My custom delegate does not work. Previously I used a custom delegate but this time it's not working. I want to pass data (UISlider value after change) from a UIViewController to a class that is subclass of UIView. Here is my code. Please help me out. -

RatingViewController.h -

#import <UIKit/UIKit.h>

@class StarRatingView; //define class, so protocol can see that class

@protocol DelegateForSlider <NSObject>   //define delegate protocol

- (void) getValue:(CGFloat) value;  //define delegate method to be implemented within another class

@end


@interface RatingViewController : UIViewController

@property (nonatomic, weak) id <DelegateForSlider> delegate; //define DelegateForSlider as delegate
@property (weak, nonatomic) IBOutlet UIView *ratingView;
- (IBAction)sliderValueChange:(id)sender;
@property (weak, nonatomic) IBOutlet UISlider *slider;

@end

RatingViewController.m -

#import "RatingViewController.h"
#import "StarRatingView.h"

@interface RatingViewController ()

@end

@implementation RatingViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    StarRatingView* starViewWithAnimated = [[StarRatingView alloc]initWithFrame:CGRectMake(5, 8, 100, 50) andRating:49];
    [self.ratingView addSubview:starViewWithAnimated];
}

- (IBAction)sliderValueChange:(id)sender {
    NSLog(@"Value Changed");
    [self.delegate getValue:self.slider.value];
}

@end

And In this class I want to get that UISlider value. StarRatingView.h -

#import <UIKit/UIKit.h>
#import "RatingViewController.h"

@interface StarRatingView : UIView <DelegateForSlider>

- (id)initWithFrame:(CGRect)frame andRating:(int)rating;

@end

StarRatingView.m -

#import "StarRatingView.h"

@interface StarRatingView()

@property (strong, nonatomic) RatingViewController *ratingViewController;
@property (nonatomic, strong) UILabel* label;

@end

@implementation StarRatingView

- (id)initWithFrame:(CGRect)frame andRating:(int)rating {
    self = [super initWithFrame:frame];
    if (self) {
        _ratingViewController.delegate = self;

        //Add label after star view to show rating as percentage
        self.label = [[UILabel alloc]initWithFrame:CGRectMake(0, 0,frame.size.width, frame.size.height)];
        self.label.font = [UIFont systemFontOfSize:18.0f];
        self.label.text = [NSString stringWithFormat:@"%d%%",rating];
        self.label.textAlignment = NSTextAlignmentRight;
        self.label.textColor = [UIColor whiteColor];
        self.label.backgroundColor = [UIColor blueColor];
        [self addSubview:self.label];
    }

    return self;
}

-(void) getValue:(CGFloat)value {
    NSLog(@"Got Value : %f", value);//This line does print nothing, I mean never fire
}

@end

Solution

  • You need to set the delegate in RatingViewController.m's viewDidLoad method. The delegate isn't being set as is because when initWithFrame:andRating: is called, _ratingViewController is nil.

    Also, it is bad practice to have a reference to a UIViewController in a UIView. Not only will it create a retain cycle, but it ignores half the reason of using delegates: to add the flexibility that any object that conforms to DelegateForSlider can be set to StarRatingView's delegate property.

    For more information on delegation check out This programming overflow post and Apple's docs