`
啸笑天
  • 浏览: 3465643 次
  • 性别: Icon_minigender_1
  • 来自: China
社区版块
存档分类
最新评论

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:@"88888888@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

 

原来的问题:

这些新增的方法和属性用于改进我们的编程方式。那么让我们先看看以前的对于UIViewController的使用有什么潜在的问题,认清问题,我们才能理解苹果改变的意义。

在以前,一个UIViewController的View可能有很多小的子view。这些子view很多时候被盖在最后,我们在最外层ViewController的viewDidLoad方法中,用addSubview增加了大量的子view。这些子view大多数不会一直处于界面上,只是在某些情况下才会出现,例如登陆失败的提示view,上传附件成功的提示view,网络失败的提示view等。但是虽然这些view很少出现,但是我们却常常一直把它们放在内存中。另外,当收到内存警告时,我们只能自己手工把这些view从super view中去掉。

改变:

苹果新的API增加了addChildViewController方法,并且希望我们在使用addSubview时,同时调用[self addChildViewController:child]方法将sub view对应的viewController也加到当前ViewController的管理中。对于那些当前暂时不需要显示的subview,只通过addChildViewController把subViewController加进去。需要显示时再调用transitionFromViewController:toViewController:duration:options:animations:completion方法。

另外,当收到系统的Memory Warning的时候,系统也会自动把当前没有显示的subview unload掉,以节省内存。

 

 

参考:https://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html

https://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html#//apple_ref/doc/uid/TP40007457-CH10

 

关于addChildViewController使用的例子:

ios5中UIViewController addChildViewController等新方法 

联想:在category中使用iOS扩展机制 - associative 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

分享到:
评论

相关推荐

    ios自定义回调方法Demo

    在iOS开发中,自定义回调方法是实现特定功能或交互的关键技术之一。它允许我们根据应用程序的需求,在不同组件之间传递信息或执行特定操作。本文将深入探讨如何在iOS中创建和使用自定义回调方法,以及它们在实际项目...

    ios实现viewcontroller切换传值的三种方法

    这里我们将详细探讨三种在iOS中实现ViewController切换并传值的方法:代理(Delegation)、键值编码(Key-Value Coding,KVC)和封装在自定义初始化方法中的参数。 **1. 代理(Delegation)** 代理是iOS开发中最...

    导航控制器presentViewController

    这个方法接收三个参数:需要呈现的视图控制器、是否需要动画效果以及呈现完成后的回调。当调用这个方法时,`viewControllerToPresent`会被显示出来,而当前视图控制器则成为其父控制器。 在导航控制器中使用`...

    iOS_MVC_轻量化ViewController

    5. **利用Delegation和Closure**:通过委托(Delegation)和闭包(Closure)来传递事件和回调,减少ViewController之间的直接依赖。 6. **使用Cell和Nibs**:对于复杂的界面,可以将UI组件(如TableViewCell)定义...

    CS193P_6_ViewController

    从提供的文件信息中,我们可以提取出几个关键的知识点,这些知识点与iPhone应用程序开发中设计模式和组件有关,特别是关于Model-View-Controller(MVC)设计模式以及ViewController的使用。 首先,文件标题“CS193P...

    iOS之presentViewController模态全屏适配解决方案.docx

    iOS之presentViewController模态全屏适配解决方案 .isPresentViewController模态全屏适配是iOS开发中的一项重要技术问题。从iOS 13.0开始,默认的模态显示视图从全屏变成了Sheet卡片样式的非全屏模式。这使得许多...

    swift-实现类似于Facebook的滑动和滚动拉消失的Viewcontroller

    在这个方法中,我们可以获取滚动视图的contentOffset,根据其变化来同步更新ViewController的消失状态。 实现过程中,为了确保滑动和滚动的平滑过渡,可能需要自定义一些动画。`UIView.animate(withDuration:...

    重新创建vvebo应用手势。删除tableView单元格或呈现新viewController的绝妙方法_Objectiv.zip

    2. 执行手势处理:在手势的识别回调中,开发者会检查手势的状态并根据需要执行相应的动作,比如删除单元格或呈现新的控制器。 3. 动画逻辑:为了实现平滑过渡,可能会有一个专门的方法来处理动画,包括单元格的淡出...

    IOS强制子VIEWCONTROLLER为横屏

    4. **处理旋转回调**:为了确保横屏ViewController正确显示,你需要监听屏幕方向的改变。可以通过`viewWillTransition(to size: with coordinator:)`方法来调整界面布局,确保内容适应新的横屏尺寸。 ```swift ...

    Delegate&Block作回调

    在iOS开发中,回调是一种非常重要的机制,它允许我们在某个操作完成时得到通知或执行相应的代码。本示例主要探讨了两种回调方式:Delegate(代理)和Block(块)。这两种方式各有特点,开发者可以根据实际需求选择...

    两个viewcontroller的界面切换

    "两个viewcontroller的界面切换"这一主题涉及到如何在iPhone应用程序中平滑地从一个ViewController过渡到另一个,同时实现动画效果,以提供良好的用户体验。在这个过程中,我们可以使用多种方法来实现这种切换,包括...

    iOSm界面跳转和参数传递之presentViewController与dismissViewControllerAnimated

    `presentViewController`和`dismissViewControllerAnimated`是iOS中的两个关键方法,用于在不同视图控制器之间进行切换,并且可以携带数据。本文将深入探讨这两个方法的工作原理、使用场景以及参数传递的方式。 ...

    滑动切换ViewController

    滑动切换ViewController是一种在iOS应用中常见的用户界面交互方式,它允许用户通过左右滑动屏幕在不同的ViewController之间进行切换。这种设计模式常用于新闻应用、社交媒体应用和许多其他类型的App,为用户提供流畅...

    ViewController的使用方法

    在iOS应用开发中,ViewController扮演了核心的角色,用于管理应用程序的视图层次结构。其核心职责包括处理用户输入、视图的展示以及数据的展示。本文将详细解释ViewController的使用方法,尤其是UITabBarController...

    使用Delegate在两个ViewController间传值

    2. 设置委托:在发送值的ViewController中,声明一个类型为上述协议的变量,用于存储委托对象。在接收到值后,会调用这个委托对象的方法。 ```swift class SenderViewController: UIViewController { weak var ...

    presentViewController:如何不覆盖原先的viewController界面

    在iOS应用开发中,`presentViewController:animated:completion:` 是一个常用的方法,用于将一个新的视图控制器(UIViewController)呈现到当前的视图控制器之上。然而,通常情况下,这个方法会完全遮挡掉原先的视图...

    自定义presentViewController的转场动画(Swift)

    本篇文章将深入探讨如何在Swift中自定义`presentViewController`的转场动画,帮助开发者创建出独特且吸引人的界面过渡效果。 首先,我们需要了解`UIViewControllerTransitioningDelegate`协议。这个协议提供了...

    半透明ViewController

    在iOS开发中,半透明(或称为玻璃效果)的ViewController是一种常见的设计手法,它能够为用户界面增添一种轻盈、通透的视觉感受。这种效果通常通过调整ViewController的背景或者子视图的透明度来实现,同时还可以...

    ViewController.m

    ViewController.m

    viewController管理

    集中管理 VC 的 方法类 集中管理 VC 的 方法类集中管理 VC 的 方法类集中管理 VC 的 方法类集中管理 VC 的 方法类集中管理 VC 的 方法类集中管理 VC 的 方法类集中管理 VC 的 方法类

Global site tag (gtag.js) - Google Analytics