使っている参考資料
- ヒレガス本第4版
- 何かほとんど本に書いてあることの写しみたくなっている…
outletとtarget、actionなど
-
outlet
- コードの側から影響を与えたいオブジェクトへのポインタ
-
action
- ユーザーがタップなどしたボタンなどのオブジェクトから送られるメッセージ
-
target
- actionを送る先のオブジェクト。ViewControllerの場合が多そう。File's Ownerとか。
stackとheap
- stack
- メソッドや関数が実行されたときにメモリが確保される場所
- heap
- クラスにallocメッセージが送られたときにメモリが確保される場所
ポインタ変数とオブジェクトの所有権(Object Ownership)
-
ポインタ変数はその変数が指し示すオブジェクトの所有権を有している。
-
オーナーがいないオブジェクトはいずれ破棄される。 <-> オーナーがいると破棄されない。
- まだ参照されているオブジェクトを破棄することは
premature deallocation
と呼ばれる。dangling pointer
とかdangling reference
として知られている。
- まだ参照されているオブジェクトを破棄することは
どのようにしてオブジェクトはオーナーを失うか
- 該当オブジェクトを参照していた変数が他のオブジェクトを参照するようになったとき
- 該当オブジェクトを参照している変数に
nil
がセットされたとき - 該当オブジェクトのオーナー自体が破棄されたとき
- コレクション内の該当オブジェクトがそのコレクションから取り除かれたとき
上記の状況でオーナーを失うことが直ちにオブジェクトの破棄に繋がるわけではない
- 他の変数が該当オブジェクトを参照していればまだそのオブジェクトは維持される
Ownership chains
- 大元のオブジェクトが破棄されれば、そこから参照されているオブジェクトが芋づる式に破棄されていく
Strong and Weak References
- ポインタ変数がオブジェクトを参照しているとき、そのオブジェクトはオーナーを持っていて、維持される。
- これを
strong reference
という
- これを
- オブジェクトを参照だけして所有権を持たないようにする変数もある。
- これを
weak reference
という
- これを
-
strong reference cycle (retain cycle)
を回避するのにweak referenceは役に立つ-
strong reference cycle (retain cycle)
とは、二つ以上のオブジェクトがお互いのstrong referenceを持っているときに起こる- こうなるとこのオブジェクトがARCで破棄されなくなるため、メモリリークの原因になる
- 片方の参照をweakにする必要が出てくる
- オブジェクトの親子関係を考えてweakにする方を決める
- 子が親へのポインタを必要としたら、そのポインタはweakにしないといけない
-
プロパティ
- Multi-threading attribute
- マルチスレッドが関わってくるかそうでないかの値
- Read/write attribute
-
readwrite
かreadonly
かの違い - デフォルトは
readwrite
-
- Memory management attribute
-
strong
,weak
,copy
,unsafe_unretained
など-
assign
はARCより前の語。
-
- デフォルト値は
strong
- デフォルト値は変わることがあるので宣言を明示するのが定石。
- 参照のタイプを示している
- オブジェクトをポイントしていないプロパティはメモリ管理する必要が無いので、常に
unsafe_unretained
である- weak referenceとは違い、参照が指し示しているオブジェクトが破棄されたときにunsafe_unretained referenceは自動で
nil
がセットされるわけではない。 - non-object propertyの場合、
unsafe_unretained
がデフォルト値。
- weak referenceとは違い、参照が指し示しているオブジェクトが破棄されたときにunsafe_unretained referenceは自動で
- NSStringとかNSMutableArrayみたいなmutable classを持つクラスのインスタンスをプロパティが指し示すときは、メモリ管理属性は
copy
をセットすべき。
-
プロパティのカスタムアクセサ
カスタムアクセサを実装すると挙動を変えられる。
- オーバーライド的な感じで書けばいい。
- 実装しているとデフォルトのアクセサは作られない
- getterとsetterを両方カスタムのものにすると、コンパイラはプロパティのインスタン変数を作らない
- 必要なときは自分で宣言する必要あり
ViewとView階層
View Hierarchy
-
全てのアプリケーションは
UIWindow
のインスタンスを一つ持っていて、これがアプリケーション内の全てのViewのコンテナになっている -
View Hierarchyが作られると、スクリーンにそれが描画される。そのプロセスは以下の2ステップに分解できる
- 階層化の全てのView(windowを含む)は自身を描画する。
CALayer
のインスタンスである自身のlayer
に自身をレンダリングする。 - 全てのViewのlayerはスクリーン上で一つにまとめられる。
- 階層化の全てのView(windowを含む)は自身を描画する。
Viewとframe
- viewの
frame
はsuperviewに対するsubviewのサイズとポジションを決める- よってviewは常に長方形
- View ControllerはアプリケーションのView階層のある一部のセットを制御するオブジェクト
drawRect:を使ってカスタム描画
- drawRect:メソッドを用いてViewのlayerにレンダリングする
-
bounds
プロパティはViewが描画するエリアを決める長方形(rectangle)である -
frame
とbounds
は異なった目的がある-
frame
は、自身以外のView階層に対するViewのlayerをレイアウトして一つにまとめる時に使われる -
bounds
は、自身のViewのlayerの境界内で描画を詳細にレイアウトするレンダリングのステップの間で使われる
-
デベロッパードキュメントの使い方
- Xcodeのメニュー -> Help -> Documentation and API Reference
- ショートカットキーは
Option-Command-?
- Shiftとか使わないとでないかもね
- ショートカットキーは
For the More Curious: Core Graphics
- drawRect:メソッドは
UIImage
,UIBezierPath
,NSString
をだいたい使う。- これらのクラスは、drawRect:が実行されたときにpixelを描画するメソッドを少なくとも一つは持っている。
- 描画は
Core Graphics
フレームワークの領分である
Views: Redrawing and UIScrollView
- ユーザがviewにタッチしたとき、そのviewに
touchesBegan:withEvent:
メッセージが送られる
クラス拡張 (Class Extensions)
- ヘッダでのプロパティ宣言とクラス拡張でのプロパティ宣言の違い
- ヘッダは他のクラスから見える。つまり、外から見えて欲しいものを宣言する
- あるクラス内部のみで使われるプロパティを宣言するときはクラス各町内で宣言する
- クラス拡張は通常、メソッド定義より前に書く
UIScrollView
- 通常、UIScrollViewはスクリーンより大きいviewを使いたいときに使う
-
UIScrollView.contentSize
はView自体の大きさ。表示している大きさはUIScrollView.frame.size
View Controllers
-
View Controllerはビュー階層を管理する
- 階層を構成するViewオブジェクトを作る
- 階層下のViewオブジェクトに関わるイベントをハンドリングする
- windowに階層を加える
-
UIViewControllerのサブクラスは
@property (nonatomic, strong) UIView *view;
というプロパティを継承している- このView Controllerのビュー階層のルートであるUIViewインスタンスを指し示す
-
View Controllerのビューは必要になるまでスクリーン上に現れない
- View Controllerが自身のビュー階層を作る方法は二通りある
- プログラムを書く。
UIViewController
のloadView
メソッドをオーバーライドする - Interface Builderを使ってNIBファイルをロードする
- プログラムを書く。
- View Controllerが自身のビュー階層を作る方法は二通りある
root view controllerを設定する
-
windowにview controllerのview階層を追加する
UIWindows's setRootViewController:
メソッド -
XIBファイル内で作られたviewオブジェクトと実行中のアプリケーション内のview controllerを関連づけるときは、
File's Owner
が関わってくる -
NIBのロードはtwo-partプロセス
- XIBにアーカイブされた全てのオブジェクトをインスタンス化し、NIBをロードするオブジェクトをFile's Ownerへ落とし込み、用意されたコネクションを確立する
-
XIBファイルとアプリを繋げるときにやること
- File's Ownerのクラスを指定する
- だいたいViewControllerのことが多い
- File's OwnerのoutletとViewをControl-Clickなどで繋げる
- ButtonなどUIViewのサブクラスのインスタンスから対応するactionにControl-dragなどで繋げる
- File's Ownerのクラスを指定する
-
outletを
weak
で宣言するのはiOSの以前のバージョンからの慣習
designated initializer of UIViewController
- View Controllerが初期化されるときにNIBの名前が
nil
だったら、View Controllerは自身のクラス名が付いたNIBファイルを探す
Loaded and Appearing Views
- viewは必要になるまでロードされない
- この遅延ロードの恩恵を受けるには、
initWithNibName:bundle:
内でview controllerのview
プロパティにアクセスしないこと
- この遅延ロードの恩恵を受けるには、
- subviewにアクセスするのは主に2つのやり方がある。
- viewDidLoadメソッドをオーバーライドする。この時、spot lazy loadingすることになる
-
UIViewController
のviewWillAppear:
メソッドを使う- 該当するviewがwindowに追加される直前にview controllerにこのメッセージが送信される
- 違い
- アプリケーションが動いているときに一度だけ設定が実行されて欲しいときは
viewDidload
を使用 - view controllerがscreenに現れる度に設定が実行されて欲しいときは
viewWillAppear
を使用
- アプリケーションが動いているときに一度だけ設定が実行されて欲しいときは
Interacting with View Controllers and Their Views
-
application:didFinishLaunchingWithOptions:
はアプリケーションが起動したときに一度だけ呼び出される。他のアプリに移ってから戻っても再び呼ばれることはない -
initWithNibName:bundle:
はUIViewControllerのdesignated initializerである。view controllerのインスタンスが作られたときに一度だけ呼び出される。同じview controllerのインスタンスが作り出される度に呼び出される。 -
loadView
はview controllerのviewをプログラミングで作る時にオーバーライドするもの -
viewDidLoad
はNIBファイルをロードしてviewを設定するときにオーバーライドするもの。view controllerのviewが作られた後に呼び出される -
viewWillAppear
はview controllerがスクリーン上に移動する度毎回呼び出される
For the More Curious: Key-Value Coding
- KVCは、名前でプロパティの値を設定したり取得したりすることが出来るメソッドのセットでNSObjectで定義されている
とりあえず訳が分からないので飛ばす。
For the More Curious: Retina Display
- Core Graphics functionを使って描画しているときはRetina、非Retina端末で見え方が変わってくることに注意
- Retina用の画像は末尾を
@2x
にする
Delegation and Text Input
UIResponder
-
UIResponderはUIKitフレームワークの抽象クラス
- 以下のスーパークラス
- UIView
- UIViewController
- UIApplication
- イベントをハンドリングするメソッドを定義している
- サブクラスでこれらのメソッドをオーバーライドすればイベントの反応の仕方をカスタマイズできる
- 以下のスーパークラス
-
タッチイベントはタッチされたビューに該当イベントが直接送られる。(Chapter5参照)
-
タッチイベント以外のイベントではどうか?
- タッチイベント以外のイベントに反応するのが誰かを示す
firstResponder
というポインタをUIWindowは持っている - ビューにfirst Responderになって欲しいときはbecomeFistResponderメッセージを送る。するとキーボードが出現する
- キーボードを隠したいときはresignFirstResponderメッセージを送る
- タッチイベント以外のイベントに反応するのが誰かを示す
-
大半のビューはfirst responderにはなれない
- 現在選択されているテキストフィールドやテキストビューからフォーカスを奪わない
-
キーボードの見た目は
UITextInputTraits
というUITextFieldのプロパティのセットで決められている- 例
- autocapitalizationType
- autocorrectionType
- enablesReturnKeyAutomatically
- keyboardType
- secureTextEntry
- 例
Protocols
-
delegateを持っている全てのオブジェクトには、対応するプロトコルがあり、そのプロトコルはオブジェクトが自身のdelegateに送ることが出来るメッセージを宣言している
- protocolは、JavaやC#でいうinterface
-
プロトコルはクラスではなく、単なるメソッド宣言のリスト
-
プロトコル内で宣言されたメソッドはrequiredかoptionalになる。デフォルトはrequired
-
optionalのメッセージを送る前に、オブジェクトは自身のdelegateに
respondsToSelector:
メッセージを送ることで「そのメッセージを送っても大丈夫か?」と確認する-
respondsToSelector:
は全てのオブジェクトが実装している- 与えられたメソッドをオブジェクトが実装しているかを実行時にチェックするメソッドである
-
-
プロトコル内のメソッドがrequiredだったらメッセージはチェックされることなく送信される
- もしdelegateが該当メソッドを実装していなかったらunrecognized selector exceptionが投げられてアプリがクラッシュする
Adding the Labels to the Screen
-
textShouldreturn:
メソッドを使って、テキストフィールドで決定ボタンを押したりしたときの動作を決めている
モーションエフェクト(Motion Effects)
-
UIInterpolatingMotionEffect
クラスを使ってモーションエフェクト関係の機能を強化できる - モーションエフェクトをテストするには、デバイス上でアプリを実行する必要がある
デバッガを使う(Using the Debugger)
- デバッガ使用の一つのやり方はブレイクポイントをセットすること
- ブレイクポイントをセットしてアプリを実行してブレイクポイントのところで止まったとき、ナビゲーションエリアにはスタックトレースが表示され、はっきりした黒字で表示されているのは自作のコード、グレーになっているのはApple関連のコードである
Stepping through code
- どこにブレイクポイントを設定したか分からないときは、breakpoint navigatorの中を見るとプロジェクト内のブレイクポイントの一覧を見ることができる
Setting an exception breakpoint
- アプリをクラッシュさせたり例外が投げられる箇所に自動的にブレイクポイントを設定できる
- navigator areaで最下部の+アイコンをクリックし、"Add Exception Breakpoint"を選択する
For the More Curious: main() and UIApplication
-
全てのアプリケーションはUIApplicationインスタンスを一つ持っている。このインスタンスはrun loopをメンテナンスする(maintaining the run loop)役目があり、一度アプリケーションのオブジェクトが作られるとこのrun loopは必然的にinfinite loopになる:
- つまり、実行しているスレッド(?)(executing thread)はmain()には永久に帰ってこない
-
もう一つUIApplicationMain関数が行うことは、UIApplicationの
delegate
として受け取られる(?)(serve as the UIApplication's delegate)クラスのインスタンスを作ることである -
全てのアプリケーション内のrun loopに加えられる最初のイベントは、アプリケーションに自身のdelegateへメッセージを送るよう促すspecial "kick-off" eventである
- そのメッセージとは
application:didFinishLaunchingWithOptions:
である
- そのメッセージとは
Silver Challenge: Pinch to Zoom
UITableとUITableViewController
-
ユーザの連絡帳内の人物一覧やApp Store内のbestsellingアイテムの一覧を表示する時は、UITableViewがその仕事を行う
-
UITableViewが表示するのはたくさんの行が加わった一列のデータである
UITableViewController
-
UITableViewはview objectである。
- アプリケーションロジックやデータは扱わない
-
UITableViewを使う時は、このTableがアプリ内で機能するためには他に何が必要が考えないといけない
- UITableViewはスクリーンに表示されるようにするためにview controllerを必要とするのが普通である
- UITableViewはdata sourceを必要とする
- UITableViewのdatasourceには、
UITableViewDataSource
プロトコルに合致している限りはObjective-Cのどんな型のオブジェクトでもなれる
- UITableViewのdatasourceには、
- UITableViewは通常、UITableViewに関わるイベントを他のオブジェクトに知らせることが出来るdelegateを必要とする。delegateは
UITableViewDelegate
プロトコルに合致している限りはどんなオブジェクトでもなれる。
-
UITableViewControllerクラスのインスタンスは以下三つの役割全てを満たすことが出来る
- view controller
- data source
- delegate
-
UITableViewControllerのviewは常にUITableViewのインスタンスであり、UITableViewControllerはUITableViewをどう用意するか、どう見せるかといったことを扱う
-
UITableViewControllerが自身のviewを作ったとき、
UITableViewのdataSourceとdelegateインスタンス変数は自動的にUITableViewControllerを指すようセットされる
Subclassing UITableViewController
UITableView's Data Source
-
Cocoa TouchにおいてUITableViewに行(rows)を与えるプロセスは典型的な手続き型プログラミングタスクとは違う
- 手続き型のデザインでは、何を表示すべきかテーブルビューに伝える
- Cocoa Touchでは、何を表示すべきかテーブルビューが他のオブジェクト(=自身の
dataSource
)に訪ねる
-
static変数はメソッドが実行し終わっても破棄されない
- global変数みたいだけど、スタック上には保持されていない
-
@classディレクティブは「該当クラスは存在するけどコンパイラはそのクラスの詳細を現在のファイルで知る必要は無いよ」とコンパイラに伝えてくれる
- @classディレクティブを使うとコンパイルが結構速くなる
- 一つファイルを変えても再コンパイルするファイルが少なくなるから。
- @classディレクティブを使うとコンパイルが結構速くなる
Implementing data source methods
-
UITableViewが表示するものを知りたいとき、UITableViewは
UITableViewDataSource
プロトコルで宣言されたメッセージ群からメッセージを送るtableView:cellForRowAtIndexPath:
tableView:numberOfRowsInSection:
-
UITableView
が自身を表示したいときはいつもdataSource
にこれらのメッセージ群(required methodsに加え、実装されたoptional methods)を送る -
Table viewはセクションに分けられる。それぞれのセクションはそれ自身特有のset of rowを持っている
UITableViewCells
- table viewのrowはviewはそれぞれviewであり、これらはUITableViewCellのインスタンスである
- cellは一つsubviewを持っており、contentViewという。contentViewは該当cellのコンテンツのsuperviewである
- UITableViewCellの実体(The real meat)はcontentViewのsubview3つである。2つは
textLabel
とdetailTextLabel
と名前の付いたUITableViewCellのプロパティで、3つ目はimageView
という名前のUIImageViewのsubviewである。 -
UITableViewCellStyle
に値を設定するとUITableViewCellの表示のされ方が変わってくる
Creating and retrieving UITableViewCells
- UITableViewCellのインスタンスを表示するとき、表示から外れたやつは再利用のためのプールに押し込められ、data sourceがそこから必要になったセルを再利用する。
- 返ってくるcellの型に注意すべし。どんなプロパティとメソッドを持っているかも。
- data sourceがtable viewに再利用できるcellを求めるとき、data sourceは文字列を渡し「このreuse identifierを持っているcellを必要としている」と伝える。
- reuse identifierは慣習としてcellクラスの名前になることが常である
Code Snippet Library
Editing UITableView
Editing Mode
-
UITableViewは
editing
プロパティを持っている-
editing
がYES
の時、 UITableViewはediting modeになる - editing modeになるとtable内のrowをユーザが操作できる
- rowの中身を編集することは出来ない
-
-
table viewは'header'という語を二つの意味で使う
- table header
- section headers
-
同様に、table footerとsection footersがあり得る
-
weak referenceはトップレベルのオブジェクトに(直接的、もしくは間接的に)所有されているオブジェクトに使う
-
XIBファイルをマニュアルでロードするときは
NSBundle
を使う- このクラスはアプリケーションとアプリケーション内で生きているapplication bundleの間のインターフェースである
-
よくあるパターン
- 必要になるまでオブジェクトを作らない(
Lazy Instantiation
)
- 必要になるまでオブジェクトを作らない(
-
UITableViewの
editing
プロパティをトグルすることも出来るが、UITableViewControllerもediting
プロパティを持っている- UITableViewControllerインスタンスは自身の
editing
プロパティとマッチするように、自身のtable viewのediting
プロパティをセットする - view controllerに
editing
プロパティをセットするには、view controllerにsetEditing:animated:
メッセージを送る
- UITableViewControllerインスタンスは自身の
Adding Rows
-
実行時にtable viewに行(row)を加えるには2つのありふれた(common)インターフェースがある
- table viewのcellの上のボタン
- だいたいレコードを追加するためのもの
- 新しく会った人の情報を連絡帳アプリを使って記録するときなど
- 緑色の+の印がついたcell。
- レコードに新たなフィールドを追加するためのもの
- ある人の誕生日の情報を連絡帳アプリ内で追加するときなど。
- table viewのcellの上のボタン
-
table viewが表示すべき行(row)の数を決めるのはUITableViewの
dataSource
である
Deleting Rows
-
table viewがrowを削除する前、table viewは自身のdata sourceに提案された削除に関するメッセージを送信する。そしてtriggerを引っ張る(pulling the trigger)前に確認メッセージ(confirmation message)を待つ
-
cellを削除するとき、2つのことをしないといけない
- UITableViewからrowを削除する
- rowにひもづいたBNRItemをBNRItemStoreから削除する
-
removeObjectIdenticalTo
メソッドはこのメソッドに渡されたオブジェクトと全く同じ(同等)のオブジェクトの時のみオブジェクトを削除する -
tableView:commitEditingStyle:forRowAtIndexPath
がdata sourceに送られるとき、2つのextra argumentsが渡される。- UITableViewCellEditingStyle
- 今回の場合、
UITableViewEditingStyleDelete
- 今回の場合、
- table内のrowのNSIndexPath
- UITableViewCellEditingStyle
Moving Rows
-
UITableView内のrowの順序を変えるためには
UITableViewDataSource
プロトコルから別のメソッドを使う-
tableView:moveRowAtIndexPath:toIndexPath:
メソッド
-
-
rowを削除するには
deleteRowsAtIndexPaths:withRowAnimation:
メッセージをUITableViewに送って削除を確認する(to confirm the deletion)
しかし、rowを移動するときは確認(confirmation)は必要ない。- table viewがそれ自身のauthorityによってrowを移動させ、その移動を自身のdata sourceに知らせる
- その時
tableView:moveRowAtIndexPath:toIndexPath:
メッセージを送る
- その時
- table viewがそれ自身のauthorityによってrowを移動させ、その移動を自身のdata sourceに知らせる
UINavigationController
- 設定アプリみたいな階層構造のビューを持ったインターフェースをdrill down interfaceという
UINavigationController
-
アプリがmultiple screens of informationを提供するとき、UINavigationControllerはそのscreensのスタックを保持する
- それぞれのscreenはUIViewControllerのviewであり、スタックはview controllersのarrayである
- UIViewControllerがスタックのトップなら、UIViewControllerのviewはvisibleになる
-
TITabBarControllerと同じく、UINavigationControllerは
viewControllers
arrayを持っている- root view controllerはこのarrayのファーストオブジェクトである
-
topViewController
プロパティはスタックのトップへのポインタを保持している
-
UINavigationControllerはUIViewControllerのサブクラスのため、自身の
view
を持っている- この
view
は常に2つのsubviewを持っている- UINavigationBar
- the view of
topViewController
- この
-
iOSアプリを書くときは、それぞれのUIViewControllerをそれ自身が小さな世界として扱うことが大切である
An Additional UIViewController
-
3つの別個のステップ
- interface fileにoutletを加える
- XIB file内でインターフェースを設定する
- それらを繋げる
-
便利なショートカット
- Command-Return-Option-Return = アシスタントエディタ表示
- Command-Return = スタンダードエディタ表示
- Command-Option-0 = ユーティリティエリアの表示・非表示切り替え
- Command-0 = ナビゲータエリアの表示・非表示切り替え
-
simulated metricsを見るためには、root level viewを選択した状態でattribute inspectorを開き、Simulated Metricsの中から適切な物を選ぶ
-
ファイルを行ったりきたりするのに使うショートカット
- ダブルクリック = 新しいタブでファイルを開く
- Command-T = ブランクタブを開く
- Coomand-Shift-}, Command-Shift-} = タブ移動
Navigating with UINavigationController
-
UINavigationControllerを使用するとき、そのスタックに納められる可能性のあるview controller全てを単純に保持することは出来ない
- navigation controllerの
viewControllers
arrayは動的である - navigation controller以外のオブジェクトがBNRDetailViewControllerのインスタンスを作る必要があり、そのインスタンスをスタックに追加する責務を負っている
- navigation controllerの
-
このオブジェクトは以下2つの要件を満たす必要がある
- BNRDetailViewControllerをいつスタックに追加する必要があるのか知っていること
- navigation controller messages、つまりpushViewcontroller:animated:メッセージを送るためにnavigation controllerへのポインタを必要としていること
-
view controllerが次のview controllerをpushするのは良くあるパターン。root view controllerは次のview controllerを作るのが良くあるし、その作られたview controller(?)は更に次のview controllerを作る。
-
新しくiOSを始めるプログラマの多くはview controller間でどのようにデータをやりとりするかについて苦労する。
- root view controllerに全てのデータを持たせ、そのデータのサブセットを次のUIViewControllerに渡す(今君がしたように)のがこのタスクをこなすのに簡潔で効率の良いやり方である。
Appearing and disappearing views
-
UINavigationControllerがviewをswapしようとするとき、UINavigationControllerは二つのメッセージを送信する。
-
viewWillDisappear
- stackから外れ(popped off)ようとしているUIViewControllerに送られるメッセージである。
-
viewWillAppear
- stackのtopになろうとするUIViewControllerに送られるメッセージである。
-
-
endEditing
メッセージがviewに送られた時、そのview自身、もしくはsubviewのどれかが現状first responderであり、そのfirst responderステータスを放棄しようとする。そしてキーボードは消える。
UINavigationBar
-
UINavigationBarが表示すべきなのは、UINavigationControllerのstackのtopに現在いるUIViewControllerへの説明的タイトル(descriptive title)である。
-
全てのUIViewControllerはUINavigationItem型(?)の
navigationItem
プロパティを持っている。- しかし、UINavigationBarと違い、UINavigationItemはUIViewのサブクラスではないので、スクリーン上に現れることが出来ない。
- その代わり、描画する必要のある中身と一緒のnavigation barを提供している
-
通常は、UINavigationItemは空である。最も基本的なレベルにおいて、UINavigationItemは簡素な
title
文字列を持っている。UIViewControllerがnavigation stackのトップに移動し、title
プロパティとして適切な文字列をnavigationItem
が持っているとき、navigation barはその文字列を表示する。 -
UINavigationItemと同じように、UIBarButtonItemはUIViewのサブクラスではない。その代わり、UINavigationItemは自身を設定するのに使用している情報をカプセル化している。同様に、UIBarButtonItemもviewではないが、UINavigationBar上にある一つのボタンがどのように表示されるべきかという情報を持っている。(UIToolbarも自身を設定するのにUIBarButtonItemのインスタンスを使っている)
-
UINavigationItemの3つ目のカスタマイズ可能なエリアはUINavigationItemの
titleView
である。文字列をタイトルとして使うことも出来るし、navigation itemの中央にUIViewのサブクラスを鎮座させることも出来る。 -
bar button itemはUIControlのtarget-actionメカニズムと同様の働きをするtarget-actionペアを持っている; タップされると、targetに対してactionメッセージを送る。
-
このactionは
SEL
型の値として渡される。SEL
型はselectorへのポインタであり、selectorはあらゆるコロンを含んだ全てのメッセージであることを思いだそう。@selector()
は返り値の型、引数の型、引数の名前を気にかけないことを覚えておこう。
Camera
Displaying Images and UIImageView
-
UIImageViewは自身の
contentMode
プロパティによって画像を表示する。このプロパティが決定するのは、image viewのframe内のコンテンツをどこに配置するか、どうやってリサイズするかということである。contentMode
に対するUIImageViewのデフォルト値はUIViewContentModeScaleToFill
である。この値は画像をimage viewの境界にちょうどマッチさせるように調整する。 -
デフォルトでは、XIBファイル内で作られるUIToolbarの新しいインスタンスはUIBarButtonItemとともにやってくる。
Touch Events and UIResponder
Touch Events
-
UIResponderのサブクラスとして、4つの別個のtouch eventsを扱う4つのメソッドをUIViewはオーバーライドできる。
- スクリーンに指がタッチしたとき
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
- スクリーン上を指が移動したとき
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
- スクリーンから指が離れたとき
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
- 電話が来たときなど、touchが終わる前にsystem eventがtouchを中断した(interrupts)ときなど
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
- スクリーンに指がタッチしたとき
-
指がスクリーンに触れたとき、UITouchのインスタンスが作られる。
指が触れたUIViewにはtouchesBegan:withEvent:メッセージが送られ、UITouchはtouches
のNSSetにセットされる。 -
スクリーン上を指が動き回るとき、touch eventはアップデートされ、スクリーン上の指の現在位置を保持する。そして、touchが始まったのと同じUIViewに
touchesMoved:withEvent:
メッセージが送られる。このメソッドに引数として渡されるNSSetは、指がスクリーンにタッチしたときに生成されるのと同じUITouchを保持する。 -
指がスクリーンから離れたとき、touch objectはアップデートされ、指の現在位置を保持するのはこれが最後である。タッチが始まったviewには
touchesEnded:withEvent:
メッセージが送られる。このメソッドが実行し終わったとき、UITouch objectは破棄される。 -
この情報からtouch objectsの働きに関する結論が以下のように得られる。
- ひとつのUITouchはスクリーン上の一つの指に対応する。このtouch objectは指がスクリーン上にある限り生き続け、その指の現在位置を絶えず保持する。
- 指が最初に触れたview(The view that the finger started on)はその指に対する全てのtouch eventメッセージを受け取る。もし最初に触れたUIViewの
frame
から指が移動して外に出た場合、そのviewはtouchesMoved:withEvent
とtouchesEnded:withEvent:
メッセージを受け取る。つまり、touchがview上で始まると、そのviewはそのtouchが生きている間、そのtouchを保持するということである。 - UITouch objectのreferenceを保持する必要はないということ。アプリケーションはtouch objectの状態が変わったときにそのtouch objectにアクセスする手段を与えてくれる。
Creating the TouchTracker Application
Drawing with BNRDrawView
Turning Touches into Lines
Handling multiple touches
For the More Curious: The Responder Chain
-
UIResponderはタッチイベントを受け取ることが出来る。
- UIViewはUIResponderのサブクラスの一つ。他にもUIViewController、UIApplication、UIWindowsなど色々ある。
-
UIViewControllerへ「直に」タッチイベントを送ることは出来ないが、view controllerは
responder chain
を通してイベントを受け取ることが出来る。 -
全てのUIResponderは
nextResponder
と呼ばれるポインタを持っていて、これらのオブジェクトが集まってresponder chainを作る。 -
UIResponderはどのようにしてイベントを「扱わない」ようにするのか?
- UIResponderは同じメッセージを
nextResponder
に送る。この仕組みは、touchesBegan:withEvent:
のようなメソッドのデフォルト実装が行うのと同じである。 - そのため、メソッドがオーバーライドされていなければ、UIResponderのnext responderがタッチイベントを処理することになる。もしapplication(responder chainの最後のオブジェクト)が該当イベントを処理しなければ、そのイベントは破棄される。
- UIResponderは同じメッセージを
For the More Curious: UIControl
UIGestureRecognizer and UIMenuController
-
よくあるジェスチャーを検出するコードを自前で書く代わりに、UIGestureRecognizerのインスタンスを使用することが出来る。
-
UIGestureRecognizerは、viewによって処理されている途中のタッチをinterceptする。
-
UIGestureRecognizer自体をインスタンス化するわけではなく、代わりにUIGestureRecognizerのサブクラスがあり、
特定をジェスチャーを認識するものを使うとよい。
Detecting Taps with UITapGestureRecognizer
Multiple Gesture Recognizers
UIMenuController
UILongPressGestureRecognizer
UIPanGestureRecognizer and Simultaneous Recognizers
For the More Curious: UIMenuController and UIResponderStandEditActions
- 通常、UIMenuControllerは表示されるときに「編集」メニューをユーザに見せる責務を負っている。
For the More Curious: More on UIGestureRecognizer
Debugging Tools
Introduction to Auto Layout
Universalizing Homepwner
The Auto Layout System
-
Auto Layout システムは一つのviewに対して別の長方形と協調する。この長方形のことを
alignment rectangle
という。 -
constraintは、view階層内に特定のrelationshipを定義し、一つもしくはそれより多くのviewに対するlayout attributeを決定する。