私の質問には、経験豊富な iOS 開発者のアドバイスが必要なようです。
私のアプリでは、3 つのサブビューで構成されるコンテナー ビュー コントローラー(クラス: CC_CosyLogContainerVC) を実装しました。
- 3 つの子ビュー コントローラーのうちの 1 つをアクティブにするボタンを含むヘッダー サブビュー、
- 一部のデータを表示する中央のサブビューと
- 子ビュー コントローラーのプレースホルダーである下のサブビュー。
コンテナー ビュー コントローラーは UINavigationController に埋め込まれており、子ビュー コントローラーがアクティブになると、その子ビュー コントローラーからもアクセスされます。子View Controllerは、必要に応じて、navigationControllerのnavigationItem.titleとnavigationItem.rightBarButtonItemsを設定します。
子View Controllerのアクティブ化と非アクティブ化のこの全体的な管理は、非常にうまく機能します。メモリリークはありません。
しかし、Instruments でさらに調査したパフォーマンスの問題を検出しました。つまり、なぜ私は問題を理解し、ここで説明できるようになったのかということです。残念ながら、私はそれを解決する方法がわかりません!
最初に、コンテナー ビュー コントローラーが読み込まれると、子ビュー コントローラーも非常に高速にビューを表示します。コンテナーのヘッダー サブビューのボタンをタップして別の子ビュー コントローラーに切り替えると、これは非常に高速に発生しますが、最初だけです。このような子の切り替えを行うたびに、これにはますます時間がかかることがわかりました。
私が見つけたインストゥルメントを使用すると、NavigationBar の「ボタン ダンス」がこの時間消費の原因であることがわかりました。子ビュー コントローラーのメイン ビューの 1 つが表示されるたびに、メソッドを呼び出して、NavigationBar で使用可能なボタンを構成します。
典型的な例として、「addCameraButton」のコードを示します。
- (void)addCameraButton
{
if ((self.cosyLogID) && ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])) {
if (!self.cameraButtonAdded) {
//add new Camera Button
UINavigationItem *myNavigationItem = (self.parentViewController ? self.parentViewController.navigationItem : self.navigationItem);
NSMutableArray *newArray = [[NSMutableArray alloc] initWithArray:myNavigationItem.rightBarButtonItems];
[newArray addObject:self.cameraButton];
myNavigationItem.rightBarButtonItems = newArray;
self.cameraButtonAdded = YES;
}
} else {
//remove old Camera Button if it already exists
[self removeCameraButton];
}
}
パフォーマンス クリティカルなコード行は次のとおりです。
myNavigationItem.rightBarButtonItems = newArray;
Instruments 時間プロファイラーは、この行がメソッド全体の 99.9% を消費していることを示しています。iPhone4 では、[addCameraButton] は初回の呼び出し時に約50 ミリ秒の時間を必要とします。2 番目の呼び出し (別の子に切り替えてから、この子に切り替えたとき) には約75 ミリ秒かかります。
広範なテストとチャイルド間の手動切り替えにより、rightBarButtonItems 配列を設定するのに必要な時間は、500 ミリ秒以上まで増加し、制限はないようです。
これにより、アプリの速度がどんどん低下するため、応答性が低下します。このナビゲーション ボタンの問題により、子ビューの表示に時間がかかります。
rightBarButtonItems を設定するときに、この増加する時間消費の問題を解決するにはどうすればよいですか?
追加情報:
メソッド [removeCameraButton]は [addCameraButton]に対応し、子の [viewWillDisappear] で呼び出されます。
- (void)removeCameraButton
{
UINavigationItem *myNavigationItem = (self.parentViewController ? self.parentViewController.navigationItem : self.navigationItem);
NSArray *oldArray = myNavigationItem.rightBarButtonItems;
NSMutableArray *newArray = [[NSMutableArray alloc] init];
BOOL doAdd;
for (id myObject in oldArray) {
doAdd = YES;
if ([myObject isKindOfClass:[UIBarButtonItem class]]) {
if ([(UIView *)myObject tag] == CC_TAG_FOR_LOGFOTOSVIEW_BTN_CAMERA) {
doAdd = NO;
}
}
if (doAdd) {
[newArray addObject:myObject];
}
}
myNavigationItem.rightBarButtonItems = newArray;
self.cameraButtonAdded = NO;
}
rightBarButtonItems 配列の観察: デバッガーで [newArray count] を確認しました。サイクルを重ねるごとに大きくなるわけではありません。間違いなく常に適切な数と種類の UIBarButtonItems が含まれています。
カメラ ボタンのGetter メソッド:
-(UIBarButtonItem *)cameraButton {
if (!_cameraButton) {
_cameraButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCamera target:self action:@selector(cameraButtonPressed:)];
_cameraButton.tag = CC_TAG_FOR_LOGFOTOSVIEW_BTN_CAMERA;
}
return _cameraButton;
}