UIBarButtonItem 内に UISearchBar を配置するとキャンセルボタンが出ない

iOS SDK 3.2.5 でアプリを作っているんだけど、UIBarButtonItem 内に UISearchBar を配置するとキャンセルボタンが出ないという細かい問題に悩まされた。

具体的には、例えば以下のように UINavigationItem に UISearchBar を入れると検索バーは表示されて入力もできるが、UISearchBar の setShowsCancelButton で YES をセットしても、なぜかキャンセルボタンが表示されない。

UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 300, 44)];

self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:searchBar] autorelease];

SDKのソースが公開されていないので理由はさっぱりわからないけど、UISearchBar の右に兄弟ビューを入れられるような構造になっていないとだめなのかなぁと思い、以下のように適当に UIView をかませてみたら、ちゃんと表示されるようになった。

UISearchBar *searchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0, 0, 300, 44)];
UIView *searchBarContainer = [[[UIView alloc] initWithFrame:searchBar.frame] autorelease];
[searchBarContainer addSubview:searchBar];

self.navigationItem.rightBarButtonItem = [[[UIBarButtonItem alloc] initWithCustomView:searchBarContainer] autorelease];

とりあえずめでたい。

それにしても、iOS SDKは妙なバグだか制限だかが多くて面倒だ。この件とか、UISplitViewController や UITabBarController のビューは root view にしないとだめだとか(UINavigationController に UISplitViewController を入れたいんですけど…)、位置とサイズを同時に変更するようなアニメーションが妙な動きをする*1とか(SafariiPadEvernoteの検索バーが拡大するような動きって、作り込みが必要なの?)、UIBarButtonSystemItemFlexibleSpace がバカで、「ツールバー中央と右だけに」ボタンを配置すると中央のボタンの位置がずれるとか*2
。ほかにもあったけど忘れた。

*1:http://stackoverflow.com/questions/2460313/animating-resizing-and-moving-uiview-at-the-same-time

*2:例: 左側のボタンが中央にならず、flexible spaceの意味がない