8

我的视图控制器正在通过该presentViewController:animated:completion:方法呈现视图。视图很好。

然后我关闭这个视图并重新呈现它并得到以下崩溃:

*** -[WebBrowser isKindOfClass:]: message sent to deallocated instance 0x1f640ac0

我的代码正在使用 ARC。这是我的 WebBrowser 类的代码,一个简单的嵌入式浏览器。

浏览器.h:

@interface WebBrowser : ITViewController <UIWebViewDelegate, UIAlertViewDelegate>

@property (nonatomic, strong) NSString *URL;
@property (nonatomic, weak) IBOutlet UIWebView *webView;
@property (nonatomic, weak) IBOutlet UIActivityIndicatorView *spinner;

- (id)initWithURL:(NSString *)URL;
- (IBAction)dismissView:(id)sender;

@end

浏览器.m:

@implementation WebBrowser

- (id)initWithURL:(NSString *)URL_ {
    self = [super initWithNibName:@"MyNib" bundle:nil];
    if (self) {
        self.URL = URL_;
    }
    return self;
}

- (void)viewDidLoad {
    [super viewDidLoad];
    self.webView.delegate = self;

    if (self.URL) {
        [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:self.URL]]];
    }
}

- (IBAction)dismissView:(id)sender {
    self.URL = nil;
    [self.webView stopLoading];
    self.webView.delegate = nil;
    [self dismissViewControllerAnimated:YES completion:NULL];
}

// + some non-related web view delegate stuff 

@end

最后,这是我在父视图控制器中呈现视图的方式:

WebBrowser *browser = [[WebBrowser alloc] initWithURL:URL];
[self presentViewController:browser animated:YES completion:NULL];

我正在运行 iOS 6 并使用 ARC 进行编译。

首先,我认为这个错误与 ARC 相关。这是我的原帖:

原帖

我注意到我的应用程序在使用 iOS 6.x 时在显示模式视图控制器并在它与以前版本的 iOS 正常工作时释放它时崩溃。

怪我还没有使用 ARC(这是我在这个项目上的下一个重要步骤),但是例如,当使用以下代码显示 Game Center 排行榜时,以下步骤:

  1. 显示排行榜
  2. 关闭排行榜
  3. 再次显示排行榜(精确更新:通过运行showLeaderboard如下所示的相同,即显示 的实例GKLeaderboardViewController

然后,发生以下错误

*** -[GKLeaderboardViewController isKindOfClass:]: message sent to deallocated instance 0x17467120

这是我的代码:

- (void)showLeaderboard {
    if ([[GKLocalPlayer localPlayer] isAuthenticated]) {
        GKLeaderboardViewController *lb = [[GKLeaderboardViewController alloc] init];
        lb.category = ...;
        lb.leaderboardDelegate = self;
        self.modalPresentationStyle = UIModalPresentationCurrentContext;
        [self presentModalViewController:lb animated:YES];
        [lb release];
    } else {
        ...
    }
}

- (void)leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController{
    [self dismissModalViewControllerAnimated:YES];
}

事实证明,删除[lb release]指令解决了我的问题,而且 iOS 5.x 也不会发生这种崩溃。

Game Center 成就视图控制器或我的任何其他自定义视图控制器显示为presentModalViewController:.

似乎用presentModalViewController:新指令替换不推荐使用的指令也presentViewController:animated:completion:不能解决问题。

4

2 回答 2

1

我看到至少一个可能的问题:

[self.webView stopLoading];
self.webView.delegate = nil;

一般来说,在调用之前设置delegate为更安全。nilstopLoading

dismissViewControllerAnimated此外,以应有的方式使用它肯定更安全,即在呈现控制器上调用它。尽管文档说明调用已传递给呈现控制器,但在方法内部正在释放的对象上调用方法并不是一个好主意。

- (IBAction)dismissView:(id)sender {
    // pass the event to the presenting controller
    // the presenting controller should call [self dismissViewControllerAnimated:YES completion:NULL];
}

- (void)viewWillDissapear {
  [super viewWillDissapear];

   //no need to do this, it's done automatically in ARC
   //self.URL = nil;

   self.webView.delegate = nil;
   [self.webView stopLoading];
}
于 2013-03-07T16:53:20.613 回答
1

编辑

根据Apple的文档,您应该从父(呈现)视图控制器中关闭视图控制器:http: //developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html#//apple_ref/doc/uid/ TP40007457-CH111-SW14

“当需要关闭呈现的视图控制器时,首选方法是让呈现的视图控制器解除它。换句话说,只要有可能,呈现视图控制器的同一个视图控制器也应该负责解除它。”

另外,您能否弄清楚哪些视图控制器正在呈现哪些,以及有多少是相互重叠的。来自苹果文档:

“如果您连续呈现多个视图控制器,从而构建一组呈现的视图控制器,则在堆栈中较低的视图控制器上调用此方法会解除其直接子视图控制器以及堆栈上该子视图上方的所有视图控制器。当这个发生时,只有最顶层的视图以动画方式被解除;任何中间视图控制器都简单地从堆栈中删除。最顶层的视图使用其模态转换样式被解除,这可能与其他视图控制器使用的样式不同在堆栈中较低的位置。”

因此,如果您认为它可能与来自 webview 的委托方法有关,您可能应该从委托属性中取消订阅视图/停止 webview 在 vi​​ewWillUnload 中加载,而不是在解除 IBAction 中,因为这不一定叫做。

我已对此进行了编辑以使其更加完整/清晰

在呈现视图之前,您需要将浏览器视图设置为具有强属性的实例变量。然后在解雇它后将其设置为零。

首先为 Modals 创建一个委托协议:

@protocol ModalViewDelegate
/**
 Delegation callback for when a modal has been dismissed
*/
- (void)modalDidDismiss:(UIViewController*)viewController;
@end

在您呈现的视图控制器界面中,订阅协议:

@interface PresentingViewController <ModalViewDelegate>
@property (nonatomic,strong) WebBrowser *browserView;
@end

在您呈现视图时的实现中:

WebBrowser *browser = [[WebBrowser alloc] initWithURL:URL];
browser.delegate = self
self.browserView = browser;
[self presentViewController:browser animated:YES completion:NULL];

在您的 WebBrowser 界面中:

@interface WebBrowser : ITViewController <UIWebViewDelegate, UIAlertViewDelegate>

@property (nonatomic, strong) NSString *URL;
@property (nonatomic, weak) IBOutlet UIWebView *webView;
@property (nonatomic, weak) IBOutlet UIActivityIndicatorView *spinner;

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

- (id)initWithURL:(NSString *)URL;
- (IBAction)dismissView:(id)sender;

@end

在您的 WebBrowser 实现中:

- (IBAction)dismissView:(id)sender {
    self.URL = nil;
    [self.webView stopLoading];
    self.webView.delegate = nil;
    [self.delegate didDismissBrowser:self];
}

回到你的父视图控制器:

- (void)didDismissBrowser:(WebBrowser*)browser
{
    if (browser == self.browserView)
    {
        [self dismissViewControllerAnimated:YES completion:NULL];
        self.browserView = nil;
    }
}
于 2013-03-07T16:58:07.393 回答