简体   繁体   中英

Objective C block becomes Nil

I am creating a custom UIView from xib called HeaderView. I have a UIButton in this HeaderView and on the button tap, i want a block to be called on ViewController in which the HeaderView is being added. Here is the code for my HeaderView.

Header File Code

@interface HeaderView : UIView

- (instancetype)initWithFrame:(CGRect)frame;

@property (copy) void(^seeAllHandler)();

@end

Implementation File Code

@interface HeaderView()

@property (weak, nonatomic) IBOutlet UILabel *titleLabel;
@property (weak, nonatomic) IBOutlet UIButton *seeAllButton;
@property (nonatomic, strong) UIView *contentView;

@end

@implementation HeaderView


- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (instancetype)initWithCoder:(NSCoder *)coder
{
    self = [super initWithCoder:coder];
    if (self) {

    }
    return self;
}

- (void)awakeFromNib
{
    [self.seeAllButton setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
    [self.seeAllButton setTitle:@"SEE ALL")  forState:UIControlStateNormal];
    [self.titleLabel setText:@"My Label")];

}

#pragma mark - Private methods

- (void)setup
{
    //Setup view from the xib file.
    self.contentView = [[[NSBundle mainBundle] loadNibNamed:NSStringFromClass(self.class) owner:self options:nil] firstObject];
    [self.contentView setFrame:self.bounds];
    [self addSubview:self.contentView];
    self.contentView.backgroundColor = [UIColor ccNordeaPink];
    self.contentView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
    self.clipsToBounds = YES;
}

- (IBAction)sellAllTapped:(UIButton *)sender {
    if(self.seeAllHandler != nil){
        self.seeAllHandler();
    }

}

@end

and here is my ViewController viewDidLoad method.

@interface ViewController () <UIScrollViewDelegate, UICollectionViewDataSource, UICollectionViewDelegate>

@property (nonatomic, strong) HeaderView *headerView;

@end



- (void)viewDidLoad
{
    [super viewDidLoad];
    [self setupSubviews];
    [self setupConstraints];

}

- (void)setupSubviews
{

    self.headerView = [[HeaderView alloc] init ];
    self.headerView.translatesAutoresizingMaskIntoConstraints = NO;

    self.headerView.seeAllHandler = ^{
        DDLogDebug(@"See all Tapped");
    };

[self.view addSubView: self.headerView];


}

The problem is that when the button is tapped the assigned block is nil and hence it is not called.

So what's happening is that you are assigning the block in viewDidLoad (via the setupSubviews method) of the ViewController. I can see that you are programmatically instantiating a HeaderView. So when you are assigning the block you are actually sending a message to an instance.

But, you are also inflating another instance by calling loadNibNamed inside the setup method of HeaderView. And that HeaderView does not have your block, and that's the one that gets shown in the UI. You've kind of got another HeaderView inside the contentView of your HeaderView.

Consequently, the actual/on-screen HeaderView instance's handler property is nil, so when it tries to fire the block back to you it is working with nil too.

The best way to approach what's happening is go into HeaderView and set a breakpoint in awakeFromNib and another breakpoint in setup . You'll see that setup gets called first. If you po self in lldb you will the address of the current instance. The next thing that happens is that awakeFromNib gets called and it hits the breakpoint there. And if you do po self again, you'll see a different address. A different instance! This is the one you are seeing in the UI. And it doesn't have the handler set!

If you want to keep this methodology for loading view hierarchy, then a simple fix is to instantiate the HeaderView from nib inside your ViewController.

So instead of doing the self.headerView = [[HeaderView alloc] init] , you do this:

self.headerView = [[[NSBundle mainBundle] loadNibNamed:@"HeaderView" owner:self options:nil] firstObject];

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM