日期:2014-05-16  浏览次数:21070 次

arc方法中局部变量viewcontroller无法获得相应回调事件( exc_bad_access)
- (IBAction)baseTap:(id)sender {
    NLMailComposerViewController *mail = [[NLMailComposerViewController alloc] init];
    mail.delegate = self;
    [self.view addSubview: mail.view];
    NSArray *toRecipients = [NSArray arrayWithObject:@"522941939@qq.com"];
    NSString *subject = @"this is subject";
    NSString *emailBody = @"this is body!";
    [mail showMailPickerToRecipients:toRecipients subject:subject emailBody:emailBody isHTML:NO];
}

- (void)emailDidFinished:(NLMailComposerViewController *)mailComposerViewController{
    NSLog(@"邮件发送后代理回调");
    //    mailComposerViewController.
    [mailComposerViewController.view removeFromSuperview];
    
}

?在baseTap方法中我要present出邮件view,由于以上代码用了arc,所以在离开baseTap方法后mail.view的controller释放了,导致emailDidFinished回调时crash。

?

当然我们可以在这个类中定义一个NLMailComposerViewController属性来解决这个办法。但总觉的这个不是理想解决方案。

?

于是在https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html中找到了答案:

Each view controller object is the sole owner of its view. You must not associate the same view object with multiple view controller objects. The only exception to this rule is that a container view controller implementation may add this view as a subview in its own view hierarchy. Before adding the subview, the container must first call its?addChildViewController:?method to create a parent-child relationship between the two view controller objects.

addChildViewController可以解决view controller无法获得相应回调事件的问题!

代码更正:

- (IBAction)baseTap:(id)sender {
    NLMailComposerViewController *mail = [[NLMailComposerViewController alloc] init];
    mail.delegate = self;
    [self.view addSubview: mail.view];
    [self addChildViewController:mail];
    NSArray *toRecipients = [NSArray arrayWithObject:@"522941939@qq.com"];
    NSString *subject = @"this is subject";
    NSString *emailBody = @"this is body!";
    [mail showMailPickerToRecipients:toRecipients subject:subject emailBody:emailBody isHTML:NO];
}

- (void)emailDidFinished:(NLMailComposerViewController *)mailComposerViewController{
    NSLog(@"邮件发送后代理回调");
    //    mailComposerViewController.
    [mailComposerViewController removeFromParentViewController];
    [mailComposerViewController.view removeFromSuperview];
    
}

?PS:

[mailComposerViewController?removeFromParentViewController]; 这个是删除 self addChildViewController加进去的view controller实例。 其view实例还是需要用 [mailComposerViewController.view removeFromSuperview]来删除。)

?

BTW:

在苹果的WWDC2011大会视频的?《Session 101 - What’s New in Cocoa》?和?《Session 102 - Implementing UIViewController Containment》?中介绍了苹果在iOS5中给UIViewController新增加的5方法以及一个属性:

// 方法 addChildViewController: removeFromParentViewController: transitionFromViewController:toViewController:duration:options:animations:completion: willMoveToParentViewController: didMoveToParentViewController: // 属性 @property(nonatomic,readonly) NSArray *childViewControllers