Twitterに流したら思ったよりも好評でしたので、ブログにも上げておきます。
こちらがiOS 2地点でのNSURLConnectionクラスを使った非同期通信のテストケース。
こちらがiOS 5でのNSURLConnectionクラスを使った非同期通信のテストケース。
Blocksはやっぱり偉大です。一つしかテストケースがないうちはまだマシなのですが、これが10個とかになると楽さが全く違ってきます。ぜひためしにURLだけ変えて同じテストケースを10個作ってみてください。iOS 5のBlocksを使ったコードはほとんどコピペだけで終わりますが、iOS 2でのdelegateを使ったコードは他にも変更しなければならない点が多数出てくるはずです。
また実際にこのコードを走らせてみると、理由はよくわからないのですがiOS 5で追加されたAPIを使ったコード(Blocks)のほうがそうでないコードよりも毎回2倍程度(0.1秒程度)高速に動作しているみたいです。ちょっと謎ですが、新しいAPIにはパフォーマンス面でのメリットもありそうです。GCDのおかげかな?
2012年1月21日土曜日
2011年11月19日土曜日
UIWebView.scrollView に対して KVO を使うと色々面白い
iOS 5より、UIWebViewにscrollViewプロパティが追加され、たとえばスクロールを無効にしたりステータスバーをタップしても一番上に戻らないようにしたりなど、UIWebViewのスクロール周りの処理を外から自由に触れるようになりました。ですが便利なのはこれだけではありません。KVOの仕組みを使うことで、さらにUIWebViewを便利に使うことができます。ここでは私が使っている中で一番のおすすめをご紹介します。
■UIWebViewの描画しているHTMLのcontentSizeを非同期的に、リアルタイムで取得する
UIWebview.scrollViewのcontentSizeプロパティは、UIWebViewの描画しているHTMLの大きさ(contentSize)と同じ値になります。この性質を利用して、contentSizeプロパティにKVOを貼ると、UIWebViewの描画しているHTMLの大きさ(contentSize)が変わったタイミングで通知を受け取ることができます。こんなコードになります。
■余談
UIWebViewのscrollViewプロパティは実はiOS 4のころからPrivate APIとして存在します。ですがiOS 5よりパブリック扱いになったおかげか、iOS 4向けのアプリでscrollViewプロパティを触っていてもリジェクトされたりクラッシュすることなく普通に使えるので非常に嬉しいです。iOS 3では使えませんのであしからず。
■UIWebViewの描画しているHTMLのcontentSizeを非同期的に、リアルタイムで取得する
UIWebview.scrollViewのcontentSizeプロパティは、UIWebViewの描画しているHTMLの大きさ(contentSize)と同じ値になります。この性質を利用して、contentSizeプロパティにKVOを貼ると、UIWebViewの描画しているHTMLの大きさ(contentSize)が変わったタイミングで通知を受け取ることができます。こんなコードになります。
- (void)viewWillAppear:(BOOL)animated { [self.webView.scrollView addObserver:self forKeyPath:@"contentSize" options:0 context:NULL]; [self.webView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://akisute.com"]]]; } - (void)viewWillDisappear:(BOOL)animated { [self.webView.scrollView removeObserver:self forKeyPath:@"contentSize"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSLog(@"%s", __func__); NSLog(@" * contentSize = %@", NSStringFromCGRect(self.webView.scrollView.contentSize)); }このテクを使うことで、例えばUIWebView自体をスクロールさせないようにした上で通知を受け取ってUIWebViewのframeをどんどん更新するようにし、UIScrollViewの中に埋め込んでしまってUIImageViewやUILabelのようにして使うみたいなUIを作ることが簡単にできます。HTMLの高さに依存するコードも作れますし、なかなか面白いですよ。iOS 5はもちろん、iOS 4でも動作します。(余談で解説)
■余談
UIWebViewのscrollViewプロパティは実はiOS 4のころからPrivate APIとして存在します。ですがiOS 5よりパブリック扱いになったおかげか、iOS 4向けのアプリでscrollViewプロパティを触っていてもリジェクトされたりクラッシュすることなく普通に使えるので非常に嬉しいです。iOS 3では使えませんのであしからず。
2011年11月18日金曜日
iOS 5の日本語キーボードの高さに対応する (iOS 3, 4, 5全対応)
iOS 5より日本語キーボードの高さが変わっているので、今まで決め打ちで高さ216pxとかやってレイアウトしていたビューが軒並み使えなくなってしまいました。今後はキーボードが出たり引っ込んだり種類が切り替わったりのタイミングできちんとキーボードの大きさを調べて適切にビューをレイアウトしてやる必要があります。ということでその対応をしたのでメモ。
前提条件として、以下の要件を満たすように作りました。
■まずはログを見てみる
キーボードの動作のタイミング、およびキーボードのframeは、NSNotificationを使って取得することができます。使用するNotification名はUIWindowのドキュメントに以下のように定義されています。
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIWindow_Class/UIWindowClassReference/UIWindowClassReference.html
■実装してみる
ということでまずはサンプルアプリを作って動かしてみて、実際に動作を見てみることにしました。大体こんな感じのコードです。
ログはこんな感じに。
iOS 5.0, iPhone 4S
前提条件として、以下の要件を満たすように作りました。
- iOS 3, 4, 5全てで正常に動作すること。iOS 3.0でも動作しなければならない。
- キーボードのframeを適切に取得できること
- キーボードが出てくるタイミング、消えるタイミング、キーボードの種類が変わるタイミング、全て取れること
■まずはログを見てみる
キーボードの動作のタイミング、およびキーボードのframeは、NSNotificationを使って取得することができます。使用するNotification名はUIWindowのドキュメントに以下のように定義されています。
http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIWindow_Class/UIWindowClassReference/UIWindowClassReference.html
// Available from iOS 2 UIKeyboardWillShowNotification UIKeyboardDidShowNotification UIKeyboardWillHideNotification UIKeyboardDidHideNotification // Available from iOS 5 UIKeyboardWillChangeFrameNotification UIKeyboardDidChangeFrameNotificationで、これらのNotification名でNSNotificationCenterにobserverを追加すると、通知が飛んできます。飛んできたNSNotificationオブジェクトのuserInfoプロパティに特定のキーでキーボードのframeが格納されているというしくみです。使えるキーは以下のとおり。
// Available from iOS 3.2 UIKeyboardFrameBeginUserInfoKey UIKeyboardFrameEndUserInfoKey // Available from iOS 3.0 UIKeyboardAnimationCurveUserInfoKey UIKeyboardAnimationDurationUserInfoKey // Available from iOS 2.0 ~ 3.2 (Deprecated in newer versions) UIKeyboardCenterBeginUserInfoKey UIKeyboardCenterEndUserInfoKey UIKeyboardBoundsUserInfoKeyiOS 3, 4, 5すべてできちんと動作しなければならないので、これらをふまえて、以下のように実装します。
- Notification名にはUIKeyboardWillShowNotification, UIKeyboardDidShowNotification, UIKeyboardWillHideNotification, UIKeyboardDidHideNotificationを使う。
- userInfoのキーには、iOS 3.0/3.1のみUIKeyboardBoundsUserInfoKeyを使い、それ以外のバージョンではUIKeyboardFrameEndUserInfoKeyを使う。
■実装してみる
ということでまずはサンプルアプリを作って動かしてみて、実際に動作を見てみることにしました。大体こんな感じのコードです。
- (void)viewWillAppear:(BOOL)animated { // Notification observerを追加する [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onUIKeyboardWillShowNotification:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onUIKeyboardDidShowNotification:) name:UIKeyboardDidShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onUIKeyboardWillHideNotification:) name:UIKeyboardWillHideNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onUIKeyboardDidHideNotification:) name:UIKeyboardDidHideNotification object:nil]; } - (void)viewWillDisappear:(BOOL)animated { // Notification observerを削除する [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)onUIKeyboardWillShowNotification:(NSNotification *)notification { NSLog(@"%s", __func__); NSLog(@" * userInfo = %@", notification.userInfo); // UIKeyboardFrameEndUserInfoKeyが使える時と使えない時で処理を分ける CGRect bounds; if (&UIKeyboardFrameEndUserInfoKey == NULL) { // iOS 3.0 or 3.1 // bounds bounds = [[notification.userInfo objectForKey:UIKeyboardBoundsUserInfoKey] CGRectValue]; } else { // それ以外 // frameだがoriginを使わないのでbounds扱いで良い bounds = [[notification.userInfo objectForKey:UIKeyboardFrameEndUserInfoKey] CGRectValue]; } // boundsを使った処理をここに書く }
ログはこんな感じに。
iOS 5.0, iPhone 4S
2011-10-19 10:35:15.007 SampleApp[5675:707] -[SampleViewController viewWillAppear:] // 前の画面の英字キーボードが一旦引っ込んで出てきている 2011-10-19 10:35:15.502 SampleApp[5675:707] -[SampleViewController onUIKeyboardDidHideNotification:] 2011-10-19 10:35:15.506 SampleApp[5675:707] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = "0.25"; UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 588}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 480}, {320, 216}}"; } 2011-10-19 10:35:15.509 SampleApp[5675:707] -[SampleViewController onUIKeyboardWillShowNotification:] 2011-10-19 10:35:15.510 SampleApp[5675:707] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = "0.35"; UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; } 2011-10-19 10:35:15.513 SampleApp[5675:707] -[SampleViewController onUIKeyboardDidShowNotification:] 2011-10-19 10:35:15.514 SampleApp[5675:707] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = "0.35"; UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; } 2011-10-19 10:35:16.162 SampleApp[5675:707] -[SampleViewController viewDidAppear:] // キーボード引っ込める 2011-10-19 10:35:44.246 SampleApp[5675:707] -[SampleViewController onUIKeyboardWillHideNotification:] 2011-10-19 10:35:44.247 SampleApp[5675:707] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = "0.25"; UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 588}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 480}, {320, 216}}"; } 2011-10-19 10:35:44.509 SampleApp[5675:707] -[SampleViewController onUIKeyboardDidHideNotification:] 2011-10-19 10:35:44.511 SampleApp[5675:707] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = "0.25"; UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 588}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 480}, {320, 216}}"; } // キーボード出す 2011-10-19 10:35:55.135 SampleApp[5675:707] -[SampleViewController onUIKeyboardWillShowNotification:] 2011-10-19 10:35:55.136 SampleApp[5675:707] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = "0.25"; UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 588}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 480}, {320, 216}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; } 2011-10-19 10:35:55.397 SampleApp[5675:707] -[SampleViewController onUIKeyboardDidShowNotification:] 2011-10-19 10:35:55.398 SampleApp[5675:707] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = "0.25"; UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 588}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 480}, {320, 216}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; } // 日本語キーボードに変更 2011-10-19 10:35:58.167 SampleApp[5675:707] -[SampleViewController onUIKeyboardWillShowNotification:] 2011-10-19 10:35:58.168 SampleApp[5675:707] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = 0; UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 252}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 390}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 354}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 228}, {320, 252}}"; } 2011-10-19 10:35:58.170 SampleApp[5675:707] -[SampleViewController onUIKeyboardDidShowNotification:] 2011-10-19 10:35:58.171 SampleApp[5675:707] * userInfo = { UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 252}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 390}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 354}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 228}, {320, 252}}"; } // 英語キーボードに変更 2011-10-19 10:36:00.483 SampleApp[5675:707] -[SampleViewController onUIKeyboardWillShowNotification:] 2011-10-19 10:36:00.484 SampleApp[5675:707] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = 0; UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 336}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 228}, {320, 252}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; } 2011-10-19 10:36:00.485 SampleApp[5675:707] -[SampleViewController onUIKeyboardDidShowNotification:] 2011-10-19 10:36:00.486 SampleApp[5675:707] * userInfo = { UIKeyboardBoundsUserInfoKey = "NSRect: {{0, 0}, {320, 216}}"; UIKeyboardCenterBeginUserInfoKey = "NSPoint: {160, 336}"; UIKeyboardCenterEndUserInfoKey = "NSPoint: {160, 372}"; UIKeyboardFrameBeginUserInfoKey = "NSRect: {{0, 228}, {320, 252}}"; UIKeyboardFrameChangedByUserInteraction = 0; UIKeyboardFrameEndUserInfoKey = "NSRect: {{0, 264}, {320, 216}}"; } // 画面を抜ける、キーボードが隠れる通知より先にviewWillDissappearされるので通知が来ない 2011-10-19 10:36:03.570 SampleApp[5675:707] -[SampleViewController viewWillDisappear:] 2011-10-19 10:36:03.986 SampleApp[5675:707] -[SampleViewController viewDidDisappear:]iOS 3.1.3, iPhone 3G
2011-10-19 10:43:46.548 SampleApp[352:207] -[SampleViewController viewWillAppear:] // 前の画面の英字キーボードが一旦引っ込んで出てきているのだが、iOS 3.1.3では引っ込む側の挙動が見られない。出てくるだけになっているようだ。 // さらにDidShowの通知がキーボードがviewDidAppearの呼び出しのあとに行われるようになっている。 // どうやらキーボードがどこに属しているのかが違うみたいだな。 2011-10-19 10:43:47.202 SampleApp[352:207] -[SampleViewController onUIKeyboardWillShowNotification:] 2011-10-19 10:43:47.210 SampleApp[352:207] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = 0.35; UIKeyboardBoundsUserInfoKey = NSRect: {{0, 0}, {320, 216}}; UIKeyboardCenterBeginUserInfoKey = NSPoint: {480, 372}; UIKeyboardCenterEndUserInfoKey = NSPoint: {160, 372}; } 2011-10-19 10:43:48.253 SampleApp[352:207] -[SampleViewController viewDidAppear:] 2011-10-19 10:43:48.315 SampleApp[352:207] -[SampleViewController onUIKeyboardDidShowNotification:] 2011-10-19 10:43:48.336 SampleApp[352:207] * userInfo = { UIKeyboardBoundsUserInfoKey = NSRect: {{0, 0}, {320, 216}}; UIKeyboardCenterBeginUserInfoKey = NSPoint: {160, 588}; UIKeyboardCenterEndUserInfoKey = NSPoint: {160, 372}; } // キーボード隠す 2011-10-19 10:43:52.854 SampleApp[352:207] -[SampleViewController onUIKeyboardWillHideNotification:] 2011-10-19 10:43:52.862 SampleApp[352:207] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = 0.300000011920929; UIKeyboardBoundsUserInfoKey = NSRect: {{0, 0}, {320, 216}}; UIKeyboardCenterBeginUserInfoKey = NSPoint: {160, 372}; UIKeyboardCenterEndUserInfoKey = NSPoint: {160, 588}; } 2011-10-19 10:43:53.183 SampleApp[352:207] -[SampleViewController onUIKeyboardDidHideNotification:] 2011-10-19 10:43:53.188 SampleApp[352:207] * userInfo = { UIKeyboardBoundsUserInfoKey = NSRect: {{0, 0}, {320, 216}}; UIKeyboardCenterBeginUserInfoKey = NSPoint: {160, 372}; UIKeyboardCenterEndUserInfoKey = NSPoint: {160, 588}; } // キーボード出す 2011-10-19 10:43:54.621 SampleApp[352:207] -[SampleViewController onUIKeyboardWillShowNotification:] 2011-10-19 10:43:54.629 SampleApp[352:207] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = 0.300000011920929; UIKeyboardBoundsUserInfoKey = NSRect: {{0, 0}, {320, 216}}; UIKeyboardCenterBeginUserInfoKey = NSPoint: {160, 588}; UIKeyboardCenterEndUserInfoKey = NSPoint: {160, 372}; } 2011-10-19 10:43:54.972 SampleApp[352:207] -[SampleViewController onUIKeyboardDidShowNotification:] 2011-10-19 10:43:54.977 SampleApp[352:207] * userInfo = { UIKeyboardBoundsUserInfoKey = NSRect: {{0, 0}, {320, 216}}; UIKeyboardCenterBeginUserInfoKey = NSPoint: {160, 588}; UIKeyboardCenterEndUserInfoKey = NSPoint: {160, 372}; } // キーボードの種類をここで英語→日本語、日本語→英語に変えているのだが、通知が来ない // だがiOS 3ではキーボードの種類によって高さが違うということが(基本)ないので気にしなくて良い [Switching to process 11779 thread 0x2e03] warning: No copy of問題なさそうですね。キーボードの種類が切り替わったタイミングにもUIKeyboardWillShowNotificationとUIKeyboardWillHideNotificationがきちんと呼ばれているようです。これならUIKeyboardWillChangeFrameNotificationを使う必要はあんまり無いように思えます。実際、UIKeyboardWillChangeFrameNotificationを使わないでUIKeyboardWillShowNotificationとUIKeyboardWillHideNotificationだけを使ったアプリをリリースしていますが、特に問題なさそうです。found locally, reading from memory on remote device. This may slow down the debug session. // 画面抜ける、viewWillDisappearより先にKeyboardが隠れる通知が来る 2011-10-19 10:44:07.442 SampleApp[352:207] -[SampleViewController onUIKeyboardWillHideNotification:] 2011-10-19 10:44:07.454 SampleApp[352:207] * userInfo = { UIKeyboardAnimationCurveUserInfoKey = 0; UIKeyboardAnimationDurationUserInfoKey = 0.35; UIKeyboardBoundsUserInfoKey = NSRect: {{0, 0}, {320, 216}}; UIKeyboardCenterBeginUserInfoKey = NSPoint: {160, 372}; UIKeyboardCenterEndUserInfoKey = NSPoint: {480, 372}; } 2011-10-19 10:44:07.472 SampleApp[352:207] -[SampleViewController viewWillDisappear:] 2011-10-19 10:44:08.374 SampleApp[352:207] -[SampleViewController viewDidDisappear:]
登録:
投稿 (Atom)