直接的な回答:
- @tc.の回答で示唆されているように、xib でビューを定義することと、View Controller (RightBarButtonItemVC) を使用して UIBarButtonItem のカスタム ビューを定義することの間には、どこかに切断があります。 RightBarButtonItemVC の代わりに呼び出します。よくわかりませんが、何かが保持されていないようです。
- 以下は、私が実装した特定の実用的なソリューションです。カテゴリを作成しましたが、前述の UIViewControllerWrapperView 用ではありません。
具体的な解決策:
まず、UIViewController の Objective-C カテゴリである BarButtonItemLoader を作成します。
@interface UIViewController (BarButtonItemLoader)
UIViewController+BarButtonItemLoader.h で、次のメソッドを定義します。
- (UIBarButtonItem *) rightBarButtonItem;
カテゴリの状態を追跡できないため、AppDelegate.h で UIBarButtonItem を定義します。
@property (strong, nonatomic) UIBarButtonItem *rightBarButtonItem;
次に、AppDelegate から rightBarButtonItem を遅延ロードして、カテゴリの rightBarButtonItem メソッドの実装を開始します (#import "AppDelegate.h" を忘れないでください)。これにより、1 つの rightBarButtonItem のみが作成され、AppDelegate に保持されます。
- (UIBarButtonItem *) rightBarButtonItem {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if(!appDelegate.rightBarButtonItem) {
//create a rightBarButtonItem (see below)
}
return appDelegate.rightBarButtonItem;
}
rightBarButtonItem に設定される UIView/UIBarButtonItem の組み立てを開始します。古い Interface Builder / xib 実装から各要素/構成を転送します。最も重要なことは、Size インスペクタのフレーム情報に注意して、.xib ファイルに手動で配置したのと同じようにサブビューをプログラムで配置できるようにすることです。
- (UIBarButtonItem *) rightBarButtonItem {
AppDelegate *appDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
if(!appDelegate.rightBarButtonItem) {
UIView *rightBarView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 264, 44)];
UIBarButtonItem *rightBarButtonItem = [[UIBarButtonItem alloc] initWithCustomView:rightBarView];
UIImageView *textHeader = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"textHeader.png"]];
textHeader.frame = CGRectMake(2, 14, 114, 20);
[rightBarView addSubview:textHeader];
UIButton *button1 = [[UIButton alloc] initWithFrame:CGRectMake(100, 2, 70, 44)];
[button1 setImage:[UIImage imageNamed:@"button1.png"] forState:UIControlStateNormal];
[button1 setImage:[UIImage imageNamed:@"button1Highlighted.png"] forState:UIControlStateHighlighted];
[button1 addTarget:self action:@selector(button1Pressed) forControlEvents:UIControlEventTouchUpInside];
[rightBarView addSubview:button1];
UIButton *button2 = [[UIButton alloc] initWithFrame:CGRectMake(194, 2, 70, 44)];
[button2 setImage:[UIImage imageNamed:@"button2.png"] forState:UIControlStateNormal];
[button2 setImage:[UIImage imageNamed:@"button2Highlighted.png"] forState:UIControlStateHighlighted];
[button2 addTarget:self action:@selector(button2Pressed) forControlEvents:UIControlEventTouchUpInside];
[rightBarView addSubview:button2];
appDelegate.rightBarButtonItem = rightBarButtonItem;
}
return appDelegate.rightBarButtonItem;
}
最後に、目的に合わせて UIViewController+BarButtonItemLoader.m に buttonXPressed メソッドを実装します。
- (void) button1Pressed {
NSLog(@"button1 Pressed");
}
- (void) button2Pressed {
NSLog(@"button2 Pressed");
}
...
このコードを任意の UIViewController またはそのサブクラスに追加して、カテゴリを使用します。
#import "UIViewController+BarButtonItemLoader.h"
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationItem.rightBarButtonItem = [self rightBarButtonItem];
}
概要
このアプローチにより、UIBarButtonItem をオンザフライで任意の UIViewController に追加できます。欠点は、作成するすべての UIViewControllers に上記のコードを追加する必要があることです。
別のオプション
UIBarButtonItems (またはその他のもの) の追加をさらにカプセル化し、各ビュー コントローラーにコードを追加する必要がないようにする場合は、BaseViewController を作成し、そこから他のすべてのビュー コントローラーをサブクラス化する必要があります。そこから、すべてのビュー コントローラーに含めたい他のアイテムを検討できます。カテゴリまたはサブクラスのルートを選択すると、粒度の問題になります。