29

手短に:

ナビコントローラーの戻るボタンのタイトルを変更すると、古いタイトルのままで新しいタイトルが表示されない場合がある。これは、再現可能な状況でのみ発生しますが、他の状況では設計どおりに機能します。

ハードウェアに依存します

  • このエラーは、iPhone 3G (iOS 4.2.1) およびシミュレーター (iOS 5.1) で発生します。
  • ソースコードが同じならiPhone 4 (iOS 5.1)でもエラーなし

タイトルに書いてある言葉にもよる

  • ボタンが作成され、自分で書いた作成メソッドから、自動的に取得されるタイトルと同じ単語 (つまり、ナビゲーション コントローラーのスタックの前のページのタイトル) を取得し、他の状況が一致すると、後でボタンのタイトルを変更しようとすると、古いテキストがスタックし、新しいタイトルが表示されません。
  • ボタンの作成時に、デフォルトのタイトルとは異なるタイトルとして単語を取得すると、デフォルトのタイトルを割り当てない限り、その後のタイトルの変更はすべて正常に機能します。
  • 多くの異なるタイトルで多くの成功した変更の後、デフォルトのタイトルである単語をボタンのタイトルに付けると、この単語は動かなくなります。それ以降の変更は受け付けません(メッセージなしで、他の状況が一致する場合のみ)

その間、ボタンが非表示だったかどうかによって異なります。

  • 別のビューがナビゲーション コントローラー スタックにプッシュされた場合、欠陥のあるボタンを含む古いページが新しいページによって非表示になり、後で新しいページがスタックから再度ポップされて、ボタンが再び表示されるようになった場合 (および他の状況が一致する場合)、古いテキストは動かなくなり、それを変更する試行は (メッセージなしで) 無視されます。
  • ボタンが非表示になったばかりの場合は、タイトルを変更しても問題ありません。私はいつも働いています。

アニメーション中に正しいタイトルが表示される

  • 上記の状況の組み合わせにより、戻るボタンのタイトルを変更する試みが無視された場合、この戻るボタンが押され、ページの右にスライドするアニメーションが実行されると、適切なタイトルが約 0.3 秒間表示されます。処理されます。アニメーションの開始時に、古いスタック タイトルが適切なタイトルに置き換えられ、アニメーション中に正しいタイトルが表示されます。

詳細な説明

UINavigationControllerの戻るボタンのテキストについてです。新しい言語設定に応じて、このボタンのタイトルを変更します。現在、私のアプリには、ナビゲーション コントローラー スタックに最大 3 つのビュー コントローラーがあります。それらのそれぞれは、UITableViewController の異なるサブクラスです。

表 1 の名前GeneralTableVCは、スタックのルート ビューです。戻るボタンはありません。アプリ内に保存した内容の概要をユーザーに提供し、設定ボタンのあるツールバーを表示します。

表 1 に表示されているのは、このツールバーを提供するナビゲーション コントローラーです。表 2 と 3 では非表示に設定されています。現時点では、そのツールバーには「設定」という名前のボタンが 1 つしかありません。この設定ボタンに触れると、テーブル 2 がスタックにプッシュされます。

名前付きの表 2 にSettingsTabVCは戻るボタンがあり、これはシミュレーターで問題を起こすものですが、iOS 5.1 を実行している実際の iPhone 4 では問題なく動作します。

表 2 の最初の行に触れると、新しい表 (表 3) が作成され、スタックにプッシュされます。

表 3 にLangSelectTableVCも戻るボタンがありますが、これは iPhone シミュレーターと実際の iPhone 4 の両方のデバイスで問題なく動作します。

表 3 は、使用可能なすべての言語 (現時点では英語とドイツ語のみ) のリストを表示する言語選択テーブルです。行に触れると、すぐに設定が変更されます。アクティブ ビュー (表 3) が再描画され、数ミリ秒以内に画面上のすべてのテキストが新しい言語で表示されます。

テーブル自体とナビゲーション バーのタイトルの再描画は問題ありません。しかし、戻るボタンのテキストも翻訳する必要があり、これは少し注意が必要です。両方の戻るボタンでまったく同じトリックを実行しましたが、表 3 に表示されている表 2 に向けられているボタンで問題なく動作します。しかし、まったく同じコードでは、シミュレーターに問題があります (実際のiPhone) を表 2 のボタンで表 1 に向けている人。

私が行ったことと何が起こっているかを示すために、いくつかのコードスニペットといくつかのスクリーンショットを提供します。


ソースコード

ARC (自動参照カウント) が使用されています。

redraw-Protocol を定義しました:

プロトコル.h

#ifndef ToDo_Project_Protocols_h
#define ToDo_Project_Protocols_h

@protocol redrawProt
- (void) mustRedraw;
@end

#endif

これは、表 1 のヘッダーです。

GeneralTableVC.h

#import <UIKit/UIKit.h>
#import "Protocols.h"
// some other imports

@interface GeneralTabVC : UITableViewController <redrawProt>

@property id<redrawProt>   parent;
@property Boolean          mustRedrawMyself;
@property NSString*        backTitle;
@property UIBarButtonItem* myBackButton;
@property UIBarButtonItem* parBackButton;

- (id) initWithParent:(id<redrawProt>)par andBackTitle:(NSString*)bT andBackButton:(UIBarButtonItem*)bB;

@end

他のテーブルのヘッダー ファイルで、同じプロパティと同一の init-functionSettingsTabVC.hを定義します。LangSelectTabVC.h

プログラムはここから始まります:

AppDelegate.m の一部

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // some code
    GeneralTabVC* genTabCon = [[GeneralTabVC alloc] initWithParent:nil andBackTitle:nil andBackButton:nil];
    UINavigationController* navCon = [[UINavigationController alloc] initWithRootViewController:genTabCon];
    // some other code
}

次は、表 1 の実装です ( GeneralTableVC.m)。SettingsTabVC.m表 2 ( ) と表 3 ( )のコードLangSelectTabVC.mは同じです。プロトコル UITableViewDataSource を実装するコードの部分は示していません。それらの部分は、問題を説明する上であまり重要ではないと思います。

このコードには、キーワードを目的の言語に翻訳するLocalizedString(keyword)とまったく同じことを行うマクロがあります。NSLocalizedString(keyword,comment)このマクロの私のバージョンは、翻訳に別のバンドルを使用します (メイン バンドルではありません)。

GeneralTableVC.m

#import "GeneralTabVC.h"
#import "SettingsTabVC.h"

#define MYTITLE @"summary"

id<redrawProt>   parent;
Boolean          mustRedrawMyself;
NSString*        backTitle;
UIBarButtonItem* myBackButton;
UIBarButtonItem* parBackButton;

@interface GeneralTabVC ()

@end

@implementation GeneralTabVC

@synthesize parent, mustRedrawMyself, backTitle, myBackButton, parBackButton;

- (void) mustRedraw {
    self.mustRedrawMyself = YES;
}

- (void) redraw {
    if ((self.parBackButton) && (self.backTitle)) {
        // Important!
        // here I change the back buttons title!
        self.parBackButton.title = LocalizedString(self.backTitle);
    }
    if (self.parent) {
        [self.parent mustRedraw];
    }
    self.title = LocalizedString(MYTITLE);
    [self.tableView reloadData];
    self.mustRedrawMyself = NO;
}

- (id) initWithParent:(id<redrawProt>)par andBackTitle:(NSString*)bT andBackButton:(UIBarButtonItem *)bB {
    self = [super initWithStyle:UITableViewStyleGrouped];
    if (self) {
        self.parent = par;
        self.mustRedrawMyself = NO;
        self.backTitle = bT;
        self.parBackButton = bB;
    }
    return self;
}

- (void) toolbarInit {
    // this method exists only in Table 1, not in other tables
    // it creates a UIBarButtonItem, adds it to self.toolbarItems
    // and makes it visible
}

- (void)SettingsAction:(id)sender {
    // this method exists only in Table 1, not in other tables
    // it will be executed after the user tabs on the settings-
    // button in the toolbar
    SettingsTabVC* setTabCon = [[SettingsTabVC alloc] initWithParent:self andBackTitle:MYTITLE andBackButton:self.myBackButton];
    [self.navigationController pushViewController:setTabCon animated:YES];
}

- (void) viewDidLoad {
    [super viewDidLoad];
    self.title = LocalizedString(MYTITLE);    
    // I want an Edit-Button. Localization of this button is
    // not yet done. At the moment is uses the systems language,
    // not the apps language.
    self.navigationItem.rightBarButtonItem = self.editButtonItem;
    [self toolbarInit];    
}

- (void) viewWillAppear:(BOOL)animated {    
    // this is an important method! Maybe here is the reason for 
    // my problem! 
    [super viewWillAppear:animated];
    // When ever this controllers view is going to appear, and  
    // when ever it is necessary to redraw it in a new language,
    // it will redraw itself:
    if (self.mustRedrawMyself) {
        [self redraw];
    }

    // And here comes the buggy back button:
    // When ever this controllers view is going to appear,
    // a new back button will be created with a title in the
    // new language:
    UIBarButtonItem* BB = [[UIBarButtonItem alloc] init];
    BB.title = LocalizedString(MYTITLE);
    self.myBackButton = BB;
    self.navigationItem.backBarButtonItem = self.myBackButton;
}

- (void) viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    // show toolbar:
    [self.navigationController setToolbarHidden:NO animated:YES];
}

// next methods are about InterfaceOrientation and the
// UITableViewDataSource protocoll. They are not important
// for the problem.

// but maybe the very last method is important. It comes in
// different versions in the three implementation files:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // This is the version of GeneralTableVC.m (Table 1)
    // It does nothing (at the actual stage of expansion, in later
    // versions it will start the main business logic of this app)
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // This is the version of SettingsTableVC.m (Table 2)
    // Tabbing onto row 0 of section 0 will push the
    // language-selection-table (Table 3) on screen:
    if (indexPath.section == 0) {
        if (indexPath.row == 0) {
            // create Table 3:
            LangSelectTabVC* langTabCon = [[LangSelectTabVC alloc] initWithParent:self andBackTitle:MYTITLE andBackButton:self.myBackButton];
            [self.navigationController pushViewController:langTabCon animated:YES];
        } else {
            // do something else (nothing at this stage of expansion)
        }
    } else {
        // do something else (nothing at this stage of expansion)
    }
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    // This is the version of LangSelectTableVC.m (Table 3)

    // here I do some magic to select and store the new language.
    // Part of this magic is transforming indexPath.row
    // into a valid language-code, putting it into the 
    // settings-object, and registering this object to 
    // NSUserDefaults
}

@end

スクリーンショット

iPhone 5.1 シミュレーターでアプリを起動すると、表 1 ( GeneralTableVC) が画面に表示されます。

アプリ起動後

画面ボタンのツールバーの右側に、設定ボタンがあります。このボタンを押すと、次の表が画面に表示されます。

設定画面

タイトル バーの [戻る] ボタンに注目してください。前の表のタイトルが「Summary」だったので、正しい「Summary」というテキストが表示されます。

Language English >次に、最初の行 (" ")にタブで移動します。

言語を変更する前に

すべて順調。では、言語を変更してみましょう。「 」のタブGerman:

言語を変更した後

わお!今はすべてドイツ語です。戻るボタンも「設定」から「Einstellungen」に変わりました。

その「Einstellungen」の戻るボタンにタブを付けましょう:

シミュレーターで戻るボタンの言語が間違っている

今はほとんど何も問題ありません。すべてがドイツ語に変わりました。「ユーバーブリック」ではなく「概要」と表示されている戻るボタン以外のすべて。実際の iPhone 4 でまったく同じソースコードを使用してまったく同じ手順を実行すると、最後の画面は次のようになります。

実際の iPhone での正しい言語

戻るボタンのテキストに注意してください。実際の iPhone 4 ではドイツ語の "Überblick" (私が欲しいもの) ですが、シミュレーターでは英語の "Summary" です。そして、これは私にとって、一部の電話 (私の iPhone 4 など) では期待どおりの結果が得られることを意味しますが、他の一部の電話 (iPhone 4S など) ではバグのある表示になる可能性があります。

私のコードの何が問題なのか、誰にもわかりませんか?


編集

編集: 2012-04-06 09:04 +02:00 (中央ヨーロッパの夏時間)

他のハードウェア、古い iPhone 3G (iOS 4.2.1) でアプリをテストすることができました。古い iPhone では、アプリはシミュレーターとまったく同じように動作します。同じアプリを iPhone 4 で実行すると、動作が異なります。

より正確には:

  • iPhone 4 (iOS 5.1) の場合: アプリは意図したとおりに動作しており、動作に問題はありません。
  • シミュレーター (iOS 5.1): アプリは、ナビゲーション コントローラーの [戻る] ボタンに間違ったタイトルを表示します。
  • iPhone 3G (iOS 4.2.1) の場合: アプリは、シミュレーターと同じ問題のある動作を示します。

編集: 2012-04-07 10:14 +02:00 (中央ヨーロッパの夏時間)

iPhone 3G のトランジションを見て、何か興味深く、おそらく役立つことに気付きました: 間違ったテキストのボタンをタブで押すと、次のことが起こります:

  1. 間違ったテキストは正しいテキストに置き換えられます
  2. この置換後、ビューはアニメーション表示されなくなり (右にスライド)、下にあるビューが表示されます。この遷移の持続時間は約 0.3 秒で、この短い間隔で、すべてのハードウェア iPhone とシミュレーターで正しいテキストが表示されます。

しかし、問題はまだあります: iPhone 3G と Simulator で誤ったテキストが表示されるのはなぜですか? iPhone 4 で常に正しいテキストが表示されるのはなぜですか?

私には、同じ場所に 2 つのボタンが重なっているかのように見えます。iPhone 4 では「私の」カスタム ボタンが前面にあり、古いシステム生成ボタンが隠されていますが、シミュレータと iPhone 3G では古いシステム生成ボタンが前面にあり、カスタム ボタンが隠されています。しかし: 非表示のカスタム ボタンがシステムで生成されたものよりも大きい (幅が広い) 場合でも、何も表示されません。スライド アウト アニメーションが開始されたときにのみ、私のボタンが表示されます。


編集: 2012-04-07 16:38 +02:00 (中央ヨーロッパの夏時間)

次の興味深い事実:

これは今までに起こったことです:

ボタンが初めて表示されたとき (2 番目のスクリーンショット、以下を参照)、タイトルとして単語を付けました。これは、システムからの前の単語と同じです。次に、ユーザーが何らかのアクションを選択すると、このボタンは別のビューによって隠されます。別のユーザーアクションの後、ボタンが再び表示され、タイトルとして新しい単語 (同じ意味ですが、新しい言語) が取得されますが、iPhone 3G およびシミュレーターでは、古いタイトルの方が「より強力」です。新しいタイトルは表示されません。古いタイトルがそのまま残っています。

これは、最初にボタンにタイトルとして単語を書き込んだ場合には発生しません。これは、システムによって生成されたタイトルとは異なります。最初のタイトルが default-title と異なる場合、後の変更はすべての iPhone とシミュレーターで実行されます。

これは、iOS が何らかの「最適化」を行っていることを私に信じさせます。ボタンの最初の外観で、カスタム タイトルがシステム生成のタイトルと同一である場合、その後のボタン タイトルの変更は無視されますが、iPhone でのみです。 3G とシミュレーター。iPhone 4 では、その後の変更はどのような場合でも許可されます。

ただし、アプリの動作不良を防ぐために、最初に別のタイトルを設定することはできません。

4

3 に答える 3

2

ご覧になっている問題は、シミュレーターで発生するシーケンスと実際のハードウェアとの間の微妙なタイミングの問題にあると思われます。

ビュー コントロールは必ずしも viewDidLoad でインスタンス化されるとは限らないため、viewWillAppear がタイトル値 (など) を設定するまで待つ必要があります。

以下は建設的な意味であり、意図された精神でそれを受け取ってください:

コードを詳細に確認しなくても、達成しようとしていることがより決定論的に達成できるのではないかと思います。あなたがやろうとしていることは難しいことでも珍しいことでもありませんが、おそらくこれらのタイミングの問題を修正しようとした結果、あなたのコードは不必要に複雑に見えます.

いくつかの簡単な例とチュートリアルを見て、フラグを使用して状態を追跡しないように (mustRedrawMyself)、これは必要ないはずなので、コードを単純化するようにしてください。viewWillAppear までビュー/コントロールのプロパティを設定しないことを忘れないでください。

ローカリゼーションの組み込みサポートを確認することもできます。

幸運を。

于 2012-04-07T09:34:16.307 に答える
0

私はこれを試してみます:

SELF REDRAW if と実行を、viewWillAppear でローカリゼーションに更新する AFTER に移動します。

タイトルを変更する前にビューに REDRAW を指示しているため、タイトルの更新は再描画の一部ではありません。それはまさにそれがすべきことです..そして私の推測では、一部のハードウェア/エミュレーターでのタイミング操作の方が高速であるため、再描画の呼び出し後に行う更新は、一部のハードウェア/エミュレーターで描画が完了する前に行われますが、描画が完了する前に終了しません。抽選は他で行われます。

操作の順序を次のように変更してみてください。それがどのように機能するかを教えてください。

- (void) viewWillAppear:(BOOL)animated {
     // this is an important method! Maybe here is the reason for 
 // my problem!  
[super viewWillAppear:animated];
// And here comes the buggy back button: 
// When ever this controllers view is going to appear, 
// a new back button will be created with a title in the  
// new language:  
UIBarButtonItem* BB = [[UIBarButtonItem alloc] init]; 
BB.title = LocalizedString(MYTITLE);
 self.myBackButton = BB; 
self.navigationItem.backBarButtonItem = self.myBackButton; 

 // When ever this controllers view is going to appear, and 
  // when ever it is necessary to redraw it in a new language,  
// it will redraw itself: 
if (self.mustRedrawMyself) { 
    [self redraw];   
}  

} 
于 2012-04-09T20:59:36.557 に答える
0

Appleサポートは答えました

その問題についてAppleサポートに連絡したところ、回答がありました。

問題は、ナビゲーション バーがナビゲーション コントローラー スタック上のビューのすべての戻るボタンを保持しており、このすべてのボタンを同時に更新する必要があることでした。viewWillAppear-Methods 内のスタックにあるビューを更新するのは良いことですが、この場所で戻るボタンを更新しようとするのは得策ではありません。


ソリューション:

UIViewController のインターフェースを拡張します。

@interface UIViewController (extended)
    - (NSString *)localizedKey;
@end

UINavigationController のスタックにビューを置く UIViewController ごとに、次のメソッドを実装します。

- (NSString*) localizedKey {
    return @"a title-keyword";
}

UIViewControllers をいじったり、いじっUIBarButtonItemたりしないでください。self.navigationItem.backBarButtonItem

タイトルを変更する必要がある場合は、次のコード スニペットを使用して、すべての [戻る] ボタンに対してそれを行います (覚えておいてください:LocalizedString(key)は に似た自己記述マクロですNSLocalizedString(key,comment))。

NSArray* vcs = [self.navigationController viewControllers];
for (UIViewController* vc in vcs) {
    vc.navigationItem.backBarButtonItem.title = LocalizedString([vc localizedKey]);
    vc.title = LocalizedString([vc localizedKey]);
}

Apple サポートの逐語的な回答:

間違ったタイミングで更新を強制することで、ナビゲーション バーと戦っています。各View Controllerのすべてのビューが適切に更新されることに注意してください。そのため、必要なものを取得するには、ナビゲーション バーに特別な注意を払う必要があります。

これを機能させるには、「viewWillAppear」を介してそれぞれが表示されるときではなく、一度に (ユーザーが言語を選択したときに) スタック上のすべてのビュー コントローラーに戻るボタンを変更する必要があります。

これには、そのボタンのローカライズされたキーをパブリックな方法で取得する機能が必要です。これを簡単に採用できるように、UIViewController にカテゴリを導入しました。

@interface UIViewController (拡張)
- (NSString *)localizedKey;
@終わり

次に、LangSelectTabVC クラスはすべての戻るボタンを一度に変更できます。このアプローチにより、ボタンのタイトルが正しく再描画されます。

したがって、viewWillAppear では、各戻るボタンを更新する必要はありません。UIKitがその更新をキャッチするには遅すぎるようです。また、更新が発生したときに、新しい戻るボタンを再作成します。これは必要ありません。現在のものを取得して、タイトルを変更してください。

NSArray *vcs = [self.navigationController viewControllers];
for (UIViewController *vc in vcs)
{
vc.navigationItem.backBarButtonItem.title = LocalizedString([vc localizedKey]);
vc.title = LocalizedString([vc localizedKey]);
}

この回避策を示す変更されたプロジェクトを添付しました。

于 2012-04-20T11:06:39.050 に答える