0

I'm trying to learn more about Objective C blocks and how they work. I've set up a simple project with two UIViewControllers embedded in a UINavigationController in Storyboard. I'm attempting to change the background color of the first ViewController's view from the second view controller. Here's some code:

ViewController.m

@implementation ViewController{
    ColorBlock _colorBlock;
}

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
    if([segue.identifier isEqualToString:@"theSegue"]){
        SecondViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"SecondViewController"];
        vc.colorBlock = _colorBlock;
    }
}

- (IBAction)moveToSecondViewController:(id)sender {
    __weak id weakSelf = self;
    _colorBlock = ^{
        [[weakSelf view] setBackgroundColor:[UIColor redColor]];
    };
}

SecondViewController.h

typedef void (^ColorBlock)(void);

@interface SecondViewController : UIViewController

@property (readwrite, copy) ColorBlock colorBlock;

@end

SecondViewController.m

- (IBAction)buttonTapped:(id)sender {
    if(self.colorBlock){
        self.colorBlock();
    }
}

The first ViewController's background color isn't being changed because in the buttonTapped: method of SecondViewController.m, self.colorBlock is nil, causing the block invocation not to be called. I thought I had successfully set the block in prepareForSegue:sender:. Why is my block property nil?

2
  • are you sure moveToSecondViewController: is called (and called before prepare for segue?) pls double check with a breakpoint in both. Commented Sep 12, 2013 at 21:21
  • Yes moveToSecondViewController: is called and my _colorBlock ivar is successfully set. Then, prepareForSegue:sender: is called and the ivar is successfully set onto SecondViewController. Commented Sep 12, 2013 at 21:24

1 Answer 1

3

In your prepareForSegue, the destination has already been instantiated. So assuming that SecondViewController is the destination, you can do:

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender{
    if([segue.identifier isEqualToString:@"theSegue"]){
        SecondViewController *vc = segue.destinationViewController;
        NSAssert([vc isKindOfClass:[SecondViewController class]], @"destination is not SecondViewController class");
        vc.colorBlock = _colorBlock;
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

@danh No, he's instantiating a new copy of SecondViewController. Thus, he's setting a property in some phantom VC that he's not segueing to.
oh. good catch. yes, this should do it. i was seeing what i was expecting in the code, not what was there. (though I think the assert is a little too defensive)
Ah yes, I forgot about that destinationViewController property. That solved it!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.