dismissModalViewControllerAnimatedの廃止


103

XCode 4.5にアップグレードして、iOSアプリをiPhone 5の4インチディスプレイで実行するように更新しましたが、次のようなビルドエラーが発生しますdismissModalViewControllerAnimated:' is deprecated

[self dismissModalViewControllerAnimated:NO];

次のように、完了ハンドラー(ただしNULLに設定)を使用して、推奨されるオーバーロードに更新してみました。

[self dismissModalViewControllerAnimated:NO completion:NULL];

しかし、この行は2つのエラーをスローします。

warning: 'TabBarController' may not respond to '-presentModalViewController:animated:completion:'
Instance method '-presentModalViewController:animated:completion:' not found (return type defaults to 'id')

ありがとう!

回答:


307

新しい方法は次のとおりです。

[self dismissViewControllerAnimated:NO completion:nil];

モーダルという単語は削除されました。現在のAPI呼び出しの場合と同様に:

[self presentViewController:vc animated:NO completion:nil];

その理由は、2012年のWWDCセッション236-iOSビデオのビューコントローラーの進化で説明されています。基本的に、このAPIによって提供されるビューコントローラーは常にモーダルではなくなり、完了ハンドラーを追加していたので、名前を変更する良い機会でした。

Marcからのコメントに応じて:

4.3以上のすべてのデバイスをサポートする最良の方法は何ですか?新しい方法はiOS4では機能しませんが、古い方法はiOS6では非推奨です。

私はこれがほぼ別の質問であることを理解していますが、誰もが3年ごとにすべてのデバイスをアップグレードするためのお金を持っているわけではないので、私たちの多くが古い(5.0より前の)デバイスを持っているので、言及する価値があると思います。それでも、私がそれを言うのが苦痛である限り、5.0未満を対象とする価値があるかどうかを検討する必要があります。5.0未満では利用できない新しいAPIがたくさんあります。そしてAppleは絶えずそれらをターゲットにすることを難しくしています。たとえば、armv6サポートはXcode 4.5から削除されました。

5.0未満をターゲットにするには(完了ブロックがnilである限り)、便利なrespondsToSelector:メソッドを使用します。

if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){
    [self presentViewController:test animated:YES completion:nil];
} else {
    [self presentModalViewController:test animated:YES];
}

Marcからの別のコメントへの応答:

これは、アプリケーションのIfステートメントでかなり多くなる可能性があります!...このコードをカプセル化するカテゴリを作成することを考えていましたが、UIViewControlerでカテゴリを作成すると拒否されますか?

フルディセントの1つ:

...コンパイラの警告を表示しないように手動で設定する方法はありますか?

まず、いいえ、UIViewControllerそれ自体でカテゴリを作成しても、アプリが拒否されることはありません。そのカテゴリメソッドがプライベートAPIまたは同様のものを呼び出さない限り。

カテゴリメソッドは、このようなコードに非常に適した場所です。また、廃止されたAPIへの呼び出しは1つしかないため、コンパイラ警告は1つしかありません。

Full Decentのコメント(質問)に対処するには、コンパイラの警告を手動で抑制できます。これがまさにその主題に関するSOの回答へのリンクです。警告を1か所で抑制するだけなので、カテゴリメソッドもコンパイラの警告を抑制するのに最適な場所です。コンパイラを無意味に黙らせることは避けた方がいいでしょう。

このための単純なカテゴリメソッドを作成する場合は、次のようになります。

@implementation UIViewController (NJ_ModalPresentation)
-(void)nj_presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)(void))completion{
    NSAssert(completion == nil, @"You called %@ with a non-nil completion. Don't do that!",NSStringFromSelector(_cmd));
    if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){
        [self presentViewController:viewControllerToPresent animated:flag completion:completion];
    } else {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
        [self presentModalViewController:viewControllerToPresent animated:flag];
#pragma clang diagnostic pop
    }
}
@end

2
4.3以上のすべてのデバイスをサポートする最良の方法は何ですか?新しい方法はiOS4では機能しませんが、古い方法はiOS6では非推奨です。ロックとハードプレイス?
2012

@Marc私はあなたの懸念に対処するために私の回答に追加しました。
NJones 2012

ありがとう。私のアプリケーションでは、これは非常に多くのIfステートメントになる可能性があります。'modalViewController'プロパティを使用するときにも同じアプローチが機能すると思います。このコードをカプセル化したカテゴリを作成することを考えていましたが、UIViewControlerでカテゴリを作成すると拒否されますか?
2012

コードについて、if ([self respondsToSelector:@selector(presentViewController:animated:completion:)]){ [self presentViewController:test animated:YES completion:nil]; } else { [self presentModalViewController:test animated:YES]; }コンパイラ警告を手動で表示しないようにする方法はありますか?
William Entriken 2013年

@FullDecentはい、できます。私はそれに関するいくつかの情報で私の答えを編集しました。
NJones 2013年

6

iOS 6以降では、次を使用できます。

[[Picker presentingViewController] dismissViewControllerAnimated:YES completion:nil];

の代わりに:

[[Picker parentViewControl] dismissModalViewControllerAnimated:YES];

...そしてあなたは使うことができます:

[self presentViewController:picker animated:YES completion:nil];

の代わりに

[self presentModalViewController:picker animated:YES];    


4

使用する

[self dismissViewControllerAnimated:NO completion:nil];

3

警告はまだそこにあります。それを取り除くために、私はそれを次のようなセレクターに入れました:

if ([self respondsToSelector:@selector(dismissModalViewControllerAnimated:)]) {
    [self performSelector:@selector(dismissModalViewControllerAnimated:) withObject:[NSNumber numberWithBool:YES]];
} else {
    [self dismissViewControllerAnimated:YES completion:nil];
}

それは私のようなOCDを持つ人々に恩恵をもたらします;)


非推奨のメソッドではrespondsToSelectorfalseが返されないので、ifステートメントを切り替える必要があります。したがって、新しいものdismissViewControllerAnimated:は、dismissModalViewControllerAnimated:完全に削除される可能性がある将来の更新まで呼び出されません。
Jsdodgers 2013

0

これは、私のような他の初心者を助ける場合に使用したpresentViewControllerの対応するバージョンです。

if ([self respondsToSelector:@selector(presentModalViewController:animated:)]) {
    [self performSelector:@selector(presentModalViewController:animated:) withObject:testView afterDelay:0];
} else {
    [self presentViewController:configView animated:YES completion:nil];
}
[testView.testFrame setImage:info]; //this doesn't work for performSelector
[testView.testText setHidden:YES];

私はViewControllerを「一般的に」使用しており、(setHiddenおよびsetImageを使用して)呼び出された内容に応じて、モーダルビューを異なるように表示することができました。以前はうまく機能していましたが、performSelectorは「設定」のものを無視するので、結局のところ、私のように効率的にしようとすると、貧弱な解決策になるようです...

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.