~117までの内容
iPhoneのアプリケーションスタイルやユーザーインターフェースの一覧
どういう分野に属するかというのをちゃんと把握しておくようにApple側が推奨している
デザインパターンみたいなのがあって、それに合致しているかを見るのだそう。
iPhone SDKの制限事項
- アクセス可能なリソースの範囲
- 公開可能なアプリケーションの種類
Interface Builderを用いたアプリケーション開発
- リソースの追加法
- テキストや画像などの属性(キャプションやサイズ、背景色など)の内容、および設定方法
- Interface Builderにあらかじめ用意されている処理をターゲット(ボタンなど)に埋め込む方法など
(たとえば、ブラウザアプリの「更新」などは、あらかじめInterface Builderに定義されている)
- 自前コードのインスタンス変数やメソッド(アクションメソッド)をInterface Builderに連携させる方法
⇒IBAction, IBOutlet
WEBブラウザ開発手順
ツールバー、WEBビューの配置、ユーザー入力のURLの受け取り、
リクエストの投げ方、WEBビューへの表示など、一連の流れ
117~219の内容
時刻表示をするアプリの開発例
時刻のアップデートのためのタイマー処理(タイマー登録)
○NSTimerの精度はあまり良くない(100ms程度)
⇒イベントキューがイベント(タイマー含む)を取り出してチェックする
という仕組みになっている(ランループという)ので、
精度を上げたければ、イベントから発生するアプリを軽くするか、マルチスレッド化する必要がある。
タイマーの開始タイミングをずらす方法(setFireDate:)
時報などに有効
サウンドの再生(AVAudioPlayerクラス)
○簡易的な再生のサポート。タイミング精度はあまり良くない
○AVFoundation.frameworkの追加が必要
○AVFoundation.hの#importが必要
リソースへのアクセス方法、バンドルについて
○iPhone OSでは、アプリケーションの実体はフォルダである
○関連するファイルを集めて、ファイルのように見せているフォルダをバンドル(パッケージ)という
○リソースへのパスがわかれば、ファイルと同様にアクセスできる
(NSBundleクラスのpathForResource:ofTypeメソッドでパスがわかる)
文字列の扱い
○@" "で生成した文字列は、NSStringのインスタンスなので、NSMutableStringに入れることはできない
(その場合は、stringWithStringというメソッドを用いて代入する)
○stringWithFormatやNSLogはprintfとほぼ同様の使い方ができる。
ただし、NSString型のようなオブジェクトを埋め込む場合には、
%sではなく、%@を使う。(%@は、内部でdescriptionメソッドを呼ぶ)
アクションメソッドの概念
○ボタンが押された時の処理など、アプリ毎に固有でOSが自動でできない処理を、
ターゲットに依頼するという方式のこと
(UIApplicationは、イベントの発生を監視していて、仮想キーボードなどの共通処理は、OSが自動でやってくれる)
デリゲートの概念
○アクションメソッドとは別に、起動処理や終了処理などアプリに固有な処理を行う部分
○デリゲートは、決められたメソッド名を持つことが特徴
○applicationDidFinishLaunching:もデリゲート
○メソッド名が固有な理由は、プロトコルで実装されているため
○Interface Builderを使う場合は、デリゲートメソッドを持つクラスを
指定のクラス(アプリケーションデリゲートであれば、UIApplication)に
デリゲートのオブジェクトとして登録しないとメソッドは呼ばれない
○アプリが起動されたとき、非アクティブになったとき、再びアクティブになったとき、終了したときなど
通知が行われ、デリゲートのメソッドが呼ばれる
○デリゲートは、実行時に差し替えが可能である
○ウェブビューや、サウンドなどにもデリゲートがある。
ウェブビューであれば、読み込みの開始、終了
サウンドであれば、再生の開始、中断、終了などのイベント時に指定のメソッドが呼ばれ、それぞれ適切に処理する
メモリ管理の詳細
○リファレンスカウントを正しく運用するルール
1.インスタンスをallocメソッドで生成したオブジェクトは、不要になった時点でreleaseメソッドを呼び出す
2.インスタンスを参照するオブジェクトは、参照する前にretainメソッドを呼び、不要になった時点でreleaseを呼び出す
⇒引数で受け取ったオブジェクトのオーナーになるときなど
○autoreleaseされるプール(NSAutoreleasePool)をOSだけにすると、
解放待ちをしているメモリがたまって問題になることがある
⇒アプリ側でNSAutoreleasePoolを生成し、autoreleaseを呼ぶと、
自動破棄されるインスタンスの登録先は
最後に生成したNSAutoreleasePoolに切り替わるので、
適切なところで、NSAutoreleasePoolの生成と破棄を行うことで、
メモリの使用量を抑えることができる(自動破棄のネストという)
○自動破棄されないインスタンスを返すメソッド
1.allocおよびallocで始まるメソッド
2.new およびnew で始まるメソッド
3.copy およびcopy で始まるメソッド
○引数がオブジェクトである場合のsetterの実装に注意
timeZone = zone;
のように単純に代入してはいけない。
今まで、timeZoneが参照していたオブジェクトを指すものがなくなり、メモリーリークしてしまうため。
if( timeZone != zone ){ [timeZone release]; timeZone = [zone retain]; }
のように今まで指していたものをreleaseし、引数で受け取ったものをretainする必要がある。
ただし、引数がintなどの場合は、
count = val;
のように単純代入でOK
プロパティの詳細
○Objective-C2.0からの機能であるため、古いメソッドがプロパティに対応していない可能性がある
⇒リファレンスやヘッダファイルを確認する必要あり
○@synthesizeで、アクセッサの名前は自動で決まるが、
getter=やsetter=でメソッド名を変えることも可能
○プロパティを指定する際、属性に単純代入であれば、assignを、
インスタンスをretainメソッドで保持する場合はretainを指定する
(上記の「メモリ管理の詳細」の最後の項目を合わせて確認)
○指定しなければスレッドセーフだが、nonatomicを指定すると排他制御されない。(速度の上昇が見込める)
スレッドセーフについて
○@synchronized( obj ){ ... }とすると、...の部分がスレッドセーフになる
アクセス中のスレッド以外のスレッドは待ち状態になる
変数に指定するプロトコル
○変数にもプロトコルを指定できる。
id <AVAudioPlayerDelegate> delegate;
⇒どんなクラスでもいいが、AVAudioPlayerDelegateプロトコルを
採用しているオブジェクトを指定せよという意味になる。
Interface Builder使用時の注意点
○プログラム中でアウトレットの宣言を削除しても、Nibファイルの中からアウトレットの設定を解除しないと
アプリケーションエラーが出てしまう(ビルドは通る)
220~312の内容
スライドショーのアプリの開発例
⇒動的に画面を切り替えるため、自作でUIをコーディングする部分含む
画像に関するコーディング(UIImage)
○UIImageは画像を扱うシンプルなクラス
○リソース内の画像からインスタンスを生成するには、imageNamed:を使用
UIImage imageNamed: @"photo1.jpg"
○リソース以外の画像ファイルからインスタンスを生成する場合は、
ファイルパスを指定するimageWithContentsOfFile: を使用
○画像サイズを保持するプロパティ
@property( nonatomic, readonly ) CGSize size;
○CGは、Core Graphicsの略で、グラフィックス関連の構造体や
関数にはCGという文字が先頭についている。
○伸縮可能な画像を生成するメソッド
stretchableImageWithLeftCapWidth: topCapHeight:
○ボタンに背景画像を張り付けるメソッド
setBackgroundImage:(画像を) forState:(このステート用に)
ステートは、通常状態、ハイライト状態、無効状態、選択状態をマクロで指定
※当該ステートの画像を指定しない場合は、通常状態のものが使われる
(その他、ボタンなどについても同様)
○ビューの可視状態を保持するプロパティは
@property( nonatomic, getter=isHidden) BOOL hidden;
※ステータスバーの可視状態は、アプリの管理を行うUIApplicationにある
sharedApplicationメソッドでインスタンスを取得し、
statusBarHiddenプロパティで取得/変更を行う
画像表示に関するコーディング(UIImageView)
○画像を表示するクラスはUIImageView
○イメージビューに表示する画像を変更したり習得したりするには、imageプロパティを使う
@property (nonatomic, retain) UIImage* image;
UIImageクラスのimageNamedで生成した画像をimageSlide.image = img;
のようにセットすればよい
○イメージビューには、複数の画像を登録して、
アニメーションさせる機能が備わっている(スライドショーで使用)
1.animationImagesにアニメする画像オブジェクトの配列を入れておく
@property( nonatomic, copy ) NSArray* animationImages;
2.animationDurationプロパティでアニメの長さ、
animationRepeatCountでアニメの繰り返し回数を設定し、
statAnimatingメソッドを呼ぶことでアニメーションが開始される。
imageSlide.animationDuration = 10.0f; //10秒 imageSlide.animationRepeatCount = 0; [imageSlide startAnimating];
3.isAnimatingメソッドでアニメーション中か否かのチェックができ、
stopAnimatingメソッドでアニメーションの停止ができる
アニメーションについて(コンポーネントのアニメーション)
○簡単なアニメーションならば、ビュークラスなどにメソッドが追加されて簡単に実現できるようになっている。
○1.beginAnimations: context:メソッドを呼んで、画面のrefreshをロック
2.アニメーション終了状態のプロパティ値を設定
3.commitAnimationsメソッドを呼んでアニメーションを開始
○アニメーションの終了とともに通常の状態に戻る
○beginAnimations: context とcommitAnimationsメソッドで囲まれた部分をアニメーションブロックと呼ぶ
○変更前と変更後が滑らかに接続されるようにアニメーションされる
⇒不透明から透明にした場合はフェードアウトし、位置を変更した場合は、滑らかに遷移する
○複数のプロパティを指定してもよい
○アニメーションの対象になるプロパティは、alpha, center(中心位置),
frame(矩形位置), bounds(大きさ), transform(座標変換)だけ
○transformの座標変換は、アフィン変換のための行列だが、専用の関数で値をセットするので、詳しく知らなくてよい。
⇒CGAffinTransformMakeRotation(回転)や、CGAffineTransformScale(拡大縮小)など
○アフィン変換が変換済みか否かは、CGAffineTransformIsIdentity関数でわかる。トグル状態を作るのに便利
○トランジッションアニメーションとは、ビューのプロパティ(位置など)に対するアニメーションではなく、
ビューの中に表示しているものに対してのアニメーションである
○画像が立体的に回転するようなフリップアニメーションや、ページがめくれるようなカールアニメーションがある
○カールアニメーションは、iPhoneシミュレータではサポートされておらず、代わりにフェードエフェクトで表示される
○ステータスバーは、setStatusBarHidden: animated:というアニメーション効果つきのメソッドを使用
○ビューのアニメーションの時間を変更する場合はsetAnimationDuration:を
アニメーションカーブ(アニメーションの遷移速度)を変更する場合は
setAnimationCurve:をアニメーションブロック内で呼ぶ。
アニメーションのカーブは、列挙型の4つの方法から1つ選択。
○トランジッションアニメは、アニメーションブロック内で画像の自前でタイマーなどを使って差し替えが必要。
ボタンに関するコーディング(UIButton)
○
ボタンのタイトルセットsetTitle: forState タイトルの文字列習得 titleForSate: ボタン画像変更 setImage: forState: ボタンの画像を習得imageForState:
○タッチのイベントで、ビューの内側にタッチして、指の外側で話した場合は、
厳密には、Touch Up Outsideというイベントが起こることになっているが、
実際に操作すると、ドラッグしてy部位をビューの外側に移動させても、
外側とは判定されず、指一本分程度はなして、やっと外側と判定される。
※指での操作はいいかげんで、ドット単位での指定が難しいので、このような余裕をもった判定をするようにしている
その他コンポーネント
○スライダのプロパティ
@property( nonatomic ) float value; //現在の値 @property( nonatomic ) float maximumValue; //最大値 @property( nonatomic ) float minimumValue; //最小値
スライダをドラッグ中に繰り返しアクションメソッドを呼ぶか、
指を離すときにだけ呼ぶかは、
@property( nonatomic, getter = isContinuous) BOOL continuous;
で設定できる。
○セグメントコントロールのセグメントの番号を保持するプロパティ
@property (nonatomic ) NSInterger selectedSegmentIndex;
乱数について
○乱数のシードは、timeIntervalSinceReferenceDateメソッドで、
経過秒数を取得し、srandに渡す(スライドショーのシャッフルで使用)
配列について
○NSArrayは、オブジェクトならなんでも登録できる・混在も可能だが、
逆に、int, float, boolなどオブジェクトでないものは登録できない。
○NSArray *imgrray = [NSArray arrayWithObjects: img1, img2, nil ];
のように、複数のオブジェクトをカンマで区切って指定
○配列に要素を登録すると、配列がretainし、配列を破棄すると、
登録されている要素すべてに対してreleaseが自動で行われる
(あらゆる配列のメソッドで同様の仕様になっている)
○NSNumberのNumberWithXxx:というクラスメソッドを使って、
どの数値型でも代入可能。取り出すときは、xxxValueというメソッドを使う
プロパティリストについて
○ファイルの一覧を
UIImage *img1 = [UIImage imageNamed: @"photo1.jpg"];
のようにソースコードに書いてしまうと、画像の差し替えや、名前の変更、画像の数などに変更があったときに大変
⇒ファイル名の一覧を外部から与えることが可能
XMLファイルを読み込んで、NSArrayのインスタンスを生成する
○XML形式のテキストファイルで、拡張子はplist
○1.リソースにXMLファイル追加しておく
2.NSBundleを使って、XMLファイルのパスを取得
3.arrayWithContentsOfFileを使用
タッチの検出について
○イメージやラベルのように
もともと画像や文字列の表示を行うことが目的で造られたビューにはアクションが定義されていない
○イメージビューはアクションの機能は持っていないため、そのままでは、イメージビューをタップしても、
なんらかのアクション(フルスクリーン化など)を起こすことができない
○しかし、UIImageViewは、UIViewの上にUIResponderというイベントを受けるクラスを継承しているため、
ユーザーのタッチ操作によるイベント処理を持っている(しかし、何も処理しないようになっているだけ)
⇒これをオーバーライドしてイベント処理を行う
○タッチの検出は、UIResponderクラスのtouchesBegan:などのメソッドで可能
引数のNSSetというのは、オブジェクトの集合クラス
オブジェクト自体は、UITouchというクラスのインスタンスである。
第2引数は、イベントの発生時刻や、タッチ情報などを含んでいる。
○タップカウントは、
@property( nonatomic, readonly ) NSUInteger tapCount;
で取得可能
○注意! ダブルタップの場合も、
tapCount==1 の状態とtapCount==2 の状態の2回分でイベントが発生する
⇒シングルタップの処理はすぐに行わず、perfomSelector: withObject: afterDelay:メソッドで
0.4秒遅らせてから実行するなどの対処が必要
タイマについて
○生成済みのタイマの間隔を変更する方法ないので、いったん止めてから再生成する。
スリープについて
○iPhoneは、ユーザーがしばらくいじらないと、自動でスリープするが、
これをしたくない場合は、UIApplicationのidleTimerDisabledプロパティをYESにしておくとよい。
Interface Builder(IB)から、Nibを読み込む際の注意
○IBでNibファイルを読み込んでメモリ上にインスタンスが復元された直後に、
awakeFromNibという関数が呼ばれる。awakeFromNibメソッド上で、
アプリケーションの初期化処理を書くのが作法になっている。
なぜなら、Nibファイルは、
1.すべてのインスタンスをalloc, init 2.Nib属性の反映 3.初期化完了してawakeFormNib
という手順をとるので、initでアプリの初期化を実行すると、
アウトレットにつながれている他のインスタンスがallocさえされていないという状況も起こりうる。
つまりinitでの初期化は早すぎる
しかも、initメソッドでインスタンスの設定を行っても、
Nibファイルの内容で上書きされてしまうので、無意味になってしまう。
⇒initには、クラス自身の初期化を記述し、awakeFromnibには、アウトレットに接続されている
インスタンスの初期化を記述するという使い分けが基本形
残り
フォント
○フォントは、フォントファミリ名⇒フォント名という階層構造になっており、
アクセス時も、この順番で取得する(familyNamesとfontNamesForFamilyName)
○fontWithName: size:でフォントクラスのインスタンスを生成
○テキストビューのfontプロパティにフォントのインスタンスをセットすると、
表示フォントが変更される。ラベルやテキストフィールド、ボタンも同様
textView.font = helv12;
○システムと同じフォントを使いたい場合は、systemFontSizeで
システムのフォントサイズを、systemFontOfSizeでシステムで使われている
フォントのインスタンスを取得可能
ピッカービュー
○1つのピッカービューで複数の項目を設定でき、項目1つ1つをコンポーネントと呼ぶ
○コンポーネントは、左から順に0から通し番号が振られる
○pickerView: widthForComponent:メソッドを実装しないとき、各コンポーネントは等間隔になる
○コンポーネント数の問い合わせや、各コンポーネントの行数の問い合わせ、指定行の文字列の問い合わせも実装が必要
テキストおよび仮想キーボードの表示/非表示
○日本語の入力はかな漢字変換を行うため、未確定のテキストが存在するが、
未確定のテキストもテキストフィールドのテキストとして書き込まれている
○未確定文字の入力通知⇒入力確定で置換の通知という2回の通知が行われる
○テキストの編集を終わらせるボタンが仮想キーボードにはない
⇒returnなどをGoなどのボタンで置き換える場合もあるが、
外部にテキストの編集の終了ボタンを設置して、そこから終了させる場合は
UIResponderクラスのresignFirstResponderメソッドを使用する
○ファーストレスポンダというのはテキスト編集に対する概念で、
画面上でテキスト入力が可能なものが複数存在する場合、仮想キーボードが
最初にどのビューに対して文字入力のイベントを送るかを決めるもの
(簡単にいうと、カーソルが表示されているもの)
○テキストのビューをタップした場合、そのビューがファーストレスポンダになる
○逆にresignFirstResponderメソッドを呼ぶとテキスト編集が終了し、
テキストビューはファーストレスポンダでなくなり、仮想キーボードも消える
⇒さらに、テキスト編集が終了するので、テキストビューデリゲートのtextViewDidEndEditing:も連鎖して呼ばれる
○ファーストレスポンダになる(自動的に仮想キーボードを表示する)場合は、becomeFirstResponderを呼ぶ
アクションシート
○選択ボタンのこと
○上のボタンから順に0,1,2という識別インデックスが付与される
○アクションシートのインスタンスは、表示後iPhone OS側に保持されるので、
アプリケーション側としてはすぐにreleaseしてよい
○どのボタンが押されたかは、インデックス値を見て分岐させる
アラート
○アクションシートに似ているが、アクションシートは下からスライドして表示される
⇒ツールバーの補助的な意味合いが強く感じられる
これに対し、アラートは中央に表示される。
○アラートのテキストは長くなるとスクロールがつき、ボタンが多くなると縦に並ぶ
○アラートのインスタンスも表示することでiPhoneOS側に保持されるので、アプリ側はすぐにreleaseしてよい。
○どのボタンが押されたかは、インデックス値を見て分岐させる
アニメーションなどをいちいち指定するのが面倒な場合
○カテゴリを使ってUIViewにコードを追加する方法がある。
UIViewのソースはないが、そのような場合にもコードを追加することができる。
配列について
○NSMutableArrayには、addObjectsFromArray:という指定した配列の要素を一括で
登録するメソッドがあり、これを使って取得した配列を末尾に追加すると便利
○配列と辞書の違い:
配列は、オブジェクトのアクセスに数字を識別子として使うが、
辞書は文字列を使ってアクセスする(連想配列を辞書と呼んでいるだけ)
ビューの反応について
○ツールバーやピッカービューはalphaプロパティを0にすると、ビューの位置をタッチしてもそのビューは反応しなくなる。
同じビューの見わけかた
○UIViewにタグがある。ビューに自由につけることができる整数値で、tagプロパティで取得参照ができる
⇒生成時にタグをセットしておき、イベント処理時に参照して分岐する
ウェブサイトの表示
○openURL:メソッドでウェブサイトを表示させる
○ただし、mailto:を指定するとメーラーが起動したり、
http://maps.google.com/を指定するとマップアプリが起動するなど、URLによって起動するアプリが変化する
○iPhoneシミュレータにはメールアプリやマップアプリは入っていないので、実機とは異なる動きをする
アプリの設定値の保存
○フォント***サイズ***テキストなどを次回のアプリケーション起動時に
復帰させる方法があり、NSUserDefaultsというクラスを使用
○このクラスのインスタンスは、アプリ起動時に自動で生成されるので、
そのインタスタンスを取得して保存したい設定値を登録用のメソッドで登録すると、
自動的にファイルを作成し、保存までを行う
○次回のアプリケーション起動時にファイルを自動的に読み込んでくれるので、
設定値の取得メソッドで値を取り出すことができる。
※ちなみにファイルというのはプロパティリストのこと
○設定値は、インスタンスやIntegerなど、
さまざまなデータを文字列の名前(キー)とセットで登録、取得するようになっている
○重要なデータなど、すぐにデータを保存したい場合は、synchronizeメソッドを呼ぶとその時点で保存が行われる
○アプリケーションの初起動時には、ファイルが存在していないので、
読み込みしても値を取得できない。そこで、設定値に対してのデフォルト値をあらかじめ設定しておくことができる
⇒ファイルから値を取得できない場合に、その値が返ってくる
アプリのフォルダ
○アプリケーションは、iPhoneにインストールされる際、アプリケーション毎に専用のフォルダが作成される
○これをアプリケーションホームと呼び、関連するファイルはこの中に格納される
プロパティリストは、Library > Preferenceフォルダの中に作られる
ローカライズ
○その国の言語や文化に適した表示や動作をすること
○ローカライズをしていないアプリケーションは、すべてのファイルがバンドルのフォルダの直下におかれる
○ローカライズする場合は、文字列ならば、Localizable.stringsという文字列リソースに書き出す
○アイコンの意味が国によって異なるなどの場合はもローカライズの対象になる
○English.lprojとJapanese.lprojというようにフォルダ分けされ、それぞれにファイルが格納されている
○共通リソースはバンドルの直下にそのまま置いておけばOK
1.バンドルの直下のてリソース
2.言語設定に対応した「XXX.lproj」フォルダ
の順でリソースを探し、当該の言語が見つからない場合は、
English.lprojの中のリソースを使用する
○ビューなどの文字は、自分でローカライズする必要があるが、プリセットボタンの「Done」などは、OS側の制御によって
自動的に表示がかわるので修正の必要がない
○アクションボタンならば、"CLEAR" = "Clear";を"CLEAR" = "クリア"のように書き換える必要がある
また、アプリケーションからNSLocalizedString関数を呼び出す必要がある
○文字列リソースのファイルエンコーディングはUTF-16でないとうまく動かないとのこと
○画像やサウンドは、pathForResourcde: ofType:メソッド自体がローカライズの
仕組みに対応しているので、適切にファイルが読み込まれるimageNamed:メソッドもローカライズに対応している
○アプリケーションタイトルは、InfoPlist.stringsというファイルを追加してローカライズする必要がある
リッチテキストについて
○UILabelではリッチテキストを表示できない ⇒ UIWebViewを使う
⇒iPhoneOSのビューで物足りないときは、HTMLで表示するのが簡単
○loadHTMLString: baseURL:メソッドで任意のHTMLをUIWebViewに読み込み可能
HTMLStringには、HTMLファイルのパスではなく、HTMLのソースを文字列で記述
baseURLには、相対パスの親パスを指定
○何も指定しないと横幅が980ピクセルあるものとしてHTMLのレイアウトを行う
⇒縮小表示されてしまうので、HTMLのMETAタグのviewportを使って画面の横幅のピクセル数を指定するとよい
○HTMLファイルをリソースとして読み込む場合は、NSURLRequestを
ウェブビューに与えて表示。ウェブビューは、JavaScriptやCSSもサポートし、マルチタッチやアニメーションも可能
○実装次第ではHTML側をトリガーにObjective-C(プログラム側)を制御できる
⇒ウェブページ読み込み事前確認のデリゲートメソッドを使って、特定の文字列を読み取ってメソッドを呼ぶ
○stringByEvaluatingJavaScriptFromString:で現在のコンテンツに対して文字列で与えたJavaScriptを
実行可能。
ただし、実行時間は5秒、メモリ使用量は最大10MB。