简体   繁体   中英

ARC custom delegate strange issue

OK, so here I have a strange problem I've been trying to figure out for the last couple of hours:

I have a simple storyboard app for iPad with two view controllers, FirstViewController which is the main view controller and a ModalViewController which appears on a Modal segue and it has a button called Done. I'm using ARC and the view controllers are specified to be for iPad.

I also have a custom delegate UIModalViewControllerDelegate which as you guess, is to dismiss the modal and pass data back to first view controller.

UIModalViewControllerDelegate.h

@protocol UIModalViewControllerDelegate <NSObject>
@required
-(void)btnDonePressed:(id)sender Values:(NSArray *)values;
@end

FirstViewController.h

@interface FirstViewController : UIViewController <UIModalViewControllerDelegate> {    
@private
    ModalViewController *mvc;
}
@end

FirstViewController.m

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
// Custom initialization
    }
    return self;
}

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

-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    mvc = [segue destinationViewController];
    mvc.delegate = self;
}

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

#pragma UIModalViewControllerDelegate

-(void)btnDonePressed:(id)sender Values:(NSArray *)values {
        ...
}

ModalViewController.h

@interface ModalViewController : UIViewController {
    __weak id<UIModalViewControllerDelegate> delegate;
}

@property (weak, nonatomic) id<UIModalViewControllerDelegate> delegate;

ModalViewController.m

@implementation ModalViewController

@synthesize delegate;

- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Custom initialization
    }
    return self;
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.navigationItem.rightBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(buttonPressed:)];
}

-(void) buttonPressed:(id) sender {
    [delegate btnDonePressed:sender Values:values];
}

Now, couple of very interesting issues:

1- In the prepare for segue, after I set the self.mvc.delegate = self; the debugger shows that the delegate is still nil (!) However, when I use NSLog(@"%@", self.mvc.delegate); I get the address of the pointer which is not nil.

2- The code above does not work, because in ModalViewController the delegate is always nil. Therefore, [delegate btnDonePressed:sender Values:values]; will never execute. I tried everything I knew might cause this issue, but nothing seem to work.

3- I guess that having a strong reference on delegate may resolve this issue but I don't want to violate the pattern and cause retain cycles issue. Does the private variable ModalViewController *mvc; in FirstViewController have issues with life cycle? When does a private variable get nilled? BTW, I also tried to replace it with @property (strong, nonatomic) ModalViewController *mvc; but nothing changed.

"I just copied the wrong version here. However, that does not resolve the issue. (I updated the code above)"

Since you mention copy-pasting. Make sure the original code has a @synthesize in there. This problem looks like a mismatch in synthesized property vs. private variable names.

@property (weak, nonatomic) id<UIModalViewControllerDelegate>delegate;

Your property as declared in combination with @synthesize will use the private variable named delegate . If you on accident leave out @synthesize a private variable with the name _delegate will be created automatically (note the underscore).

In your buttonPressed: method you access the private variable delegate directly. So that would potentially always return nil since the accessors actually use the underscored version.

Just to make sure, either remove the manually declared variable delegate or use self.delegate in your buttonPressed: method. See what happens.

Thanks everyone for the answers. I finally found the solution to this problem.

Actually, the code is perfectly correct. The problem is the UINavigationController , in which the Modal View Controller is embedded.

Instead of

myModalWindowViewController = [segue destinationViewController];
myModalWindowViewController.delegate = self;

I do

UINavigationController *navigationController = [segue destinationViewController];
myModalWindowViewController = (MyModalWindowViewController *)[navigationController.viewControllers objectAtIndex:0];
myModalWindowViewController.delegate = self;

I didn't know that when you segue to a ViewController which is embedded in a NavigationController, the DestinationViewController is the NavigationController and NOT the ViewController. My bad!

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