8

presentViewController:animated:completion:私のView Controllerは、メソッドを介してビューを提示しています。ビューはうまく表示されます。

次に、このビューを閉じて再表示すると、次のクラッシュが発生します。

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

私のコードはARCを使用しています。これは、単純な組み込みブラウザーである WebBrowser クラスのコードです。

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

WebBrowser.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 では正常に動作していたのに、モーダル ビュー コントローラーを表示してリリースすると、iOS 6.x でアプリがクラッシュすることに気付きました。

まだ ARC を使用していないのは私のせいです (これは、このプロジェクトの次の大きなステップです)。

  1. リーダーボードを表示する
  2. リーダーボードを閉じる
  3. リーダーボードを再度表示します (PRECISION UPDATE: 以下に示すものと同じものを実行します。つまり、 の新しいインスタンスを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:

また、deprecated-presentModalViewController:命令を新しい命令に置き換えてもpresentViewController:animated:completion:問題は解決しないようです。

4

2 に答える 2

1

編集

Apple のドキュメントによると、親 (提示) ビューコントローラーからビューコントローラーを却下する必要があります: http://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ModalViewControllers/ModalViewControllers.html#//apple_ref/doc/uid/ TP40007457-CH111-SW14

「提示されたView Controllerを却下するときが来たら、推奨されるアプローチは、提示側のView Controllerにそれを却下させることです。つまり、可能な限り、View Controllerを提示した同じView Controllerがそれを却下する責任も負うべきです。」

また、どのビューコントローラーがどのビューコントローラーを提示しているか、また、互いに重ね合わされている数を明確にしていただけますか。リンゴのドキュメントから:

「いくつかのView Controllerを連続して提示し、提示されたView Controllerのスタックを構築する場合、スタックの下位にあるView Controllerでこのメソッドを呼び出すと、スタックの直接の子View Controllerとその子の上のすべてのView Controllerが破棄されます。これが最上位のビューのみがアニメーション化された方法で破棄されます; 中間のビュー コントローラーは単にスタックから削除されます. 最上位のビューはモーダル トランジション スタイルを使用して破棄されますが、これは他のビュー コントローラーで使用されるスタイルとは異なる場合がありますスタックの下に。」

したがって、WebView からのデリゲート メソッドと関係があると思われる場合は、デリゲート プロパティからビューのサブスクライブを解除するか、却下 IBAction ではなく、viewWillUnload で WebView の読み込みを停止する必要があります。呼ばれます。

より完全/明確にするためにこれを編集しました

ビューを表示する前に、強いプロパティを持つインスタンス変数にブラウザー ビューを設定する必要があります。それを却下した後、それを nil に設定します。

まず、モーダルのデリゲート プロトコルを作成します。

@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 に答える
1

考えられる問題が少なくとも 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 に答える