Search code examples
objective-ccocoadelegates

Delegate does not trigger method


I've looked at other delegate questions but there weren't any good existing answers. Everything should be set up properly, I can see my slider will change value in logs. For some reason, the delegate function numberOfSquaresInSquareView() never fires when I call it from squareView, and the squareView delegate call just returns nil. I know I am fairly close since this closely matches some lessons I've found, but I think I am missing something. The changeSquareCount() works and I can see in logs that it saves the value.

squareView.h

#import <Cocoa/Cocoa.h>

NS_ASSUME_NONNULL_BEGIN
@class SquareView;
@protocol SquareViewDelegate <NSObject>

- (NSNumber *)numberOfSquaresInSquareView:(SquareView *)squareView;

@end

@interface SquareView : NSView
@property (nonatomic, weak) id<SquareViewDelegate> delegate;

@end

NS_ASSUME_NONNULL_END

squareView.m

#import "SquareView.h"

@implementation SquareView
@synthesize delegate;

- (id)initWithFrame:(NSRect)frame
{
    self = [super initWithFrame:frame];
    if (self)
    {
    }
    return self;
}

- (void)drawRect:(NSRect)dirtyRect {
    [super drawRect:dirtyRect];
    NSLog(@"drawing rect");
    [[NSColor redColor]set];

    //NSNumber *num = ; //cound pass in nil, dont matter
    NSLog(@"squares to draw: %@", [delegate numberOfSquaresInSquareView:self]);
    // Drawing code here.
}

@end

AppController.h

#import <Foundation/Foundation.h>
#import "SquareView.h"
//@class SquareView;
NS_ASSUME_NONNULL_BEGIN

@interface AppController : NSObject <SquareViewDelegate>

@property (retain) IBOutlet SquareView *squareView;

- (IBAction)changeSquareCount:(id)sender;
@end

NS_ASSUME_NONNULL_END

AppController.m

#import "AppController.h"

@implementation AppController
{
    NSNumber *_squareCount;
}
@synthesize squareView = _squareView;
- (void)awakeFromNib
{
    [_squareView setDelegate:nil];
    _squareCount = @(10);
    [_squareView setNeedsDisplay:YES];
}

- (void)changeSquareCount:(id)sender
{
    _squareCount = @([sender intValue]);
    NSLog(@"square count stored: %@",_squareCount);
    [_squareView setNeedsDisplay:YES];
}
-(NSNumber *)numberOfSquaresInSquareView:(SquareView *) squareView
{
    NSLog(@"triggering numberOfSquaresInSquareView");
    return _squareCount;
}

@end

Solution

  • The delegate has to 'retain' somewhere to make it work. As I can see here, the SquareView is a sub-view of AppController, and the delegate works like SquareView <-> AppController. It's a kind of callback in this case. However, you're assigning it to nil by [_squareView setDelegate:nil] It should be:

    _squareView.delegate = self;
    

    By doing that, every time drawRect in SquareView gets called, it will trigger numberOfSquaresInSquareView in AppController, and in this case, it will print out

    squares to draw: 10