はじめに
こんにちは、Go界のドン・チードルです。最近ちょこちょこiOS開発について調べ物したりちょろちょろいじってたので、忘れないうちにメモしておきます。ちなみに僕は最近になってiOS開発、Objective-Cを触り始めたような素人ですので、間違った理解をしているかもしれません。コメントなどいただければ幸い。
Getting Started
とりあえず公式ドキュメント読んどけばいいだろと思ったので、Appleの公式ドキュメントを読みながら手を動かしました。
これで「TODO listアプリをStoryboardとかを駆使してコードをほとんど書かずにできるよ、すごい!!」みたいなチュートリアルやったんですが、結局何がわかったのかがあいまいでわけわからなくなったので、とりあえずObjective-Cのコードを適当に書いてみることにしました。
Objective-C
最初のチュートリアルでObjective-Cがなんとなーくわかったので、今度はiOSプロジェクトではなく、普通のCLIプロジェクトを作ってみることにしました。
新規プロジェクト作成時に OS X > Application > Command Line Tool としてプロジェクトを作成すると main.m くらいしか無いプロジェクトが作成されてめちゃわかりやすい!!
とりあえず NSLog() で出力できればいいやってことで適当に色々書いて、最低限Objective-Cを書くために必要な文法だけ抑えた。
エントリポイント
main.mがエントリポイント@autoreleasepoolというプロパティでARC (Automatic Reference Counting) が呼ばれる。このブロックの中に書いておけば自動で参照カウント見て良きに計らってくれて助かる。
型
- プリミティブに
stringやらintやらあるが、iOS開発の時はあんまり使わない風 NS***といういかにもNext Step出身でございますよという拡張型が用意されているNSString(文字列)、NSInteger(整数)など- 拡張型は全部
NSObjectというクラスの拡張なので、初期化とかがめっちゃだるい- eg.
NSString *foo = [NSString stringWithCString:"だるい" encoding:NSUTF8StringEncoding];
- eg.
- でもだるすぎるので糖衣構文で
@を先頭につけると簡単に初期化出来て良い- eg.
NSString *foo = @"だるい";
- eg.
- ArrayやDictionaryもある
- eg1.
NSArray *bar = @[ @"spam", @"egg", @"ham" ]; - eg2.
NSDictionary *buz = @{ @"Monty": @"Python", @"age": @100 };
- eg1.
- Arrayはちゃんと初期化するときに、最後
nil終わりにしないといけないのに注意- eg.
NSArray *bar = [NSArray arrayWithObjects:@"spam", @"egg", @"ham", nil];
- eg.
- 基本はimmutableなので、mutableな型が欲しかったら
NSMutable***を使う。 - ARC使うので大体ポインタ型で宣言する
クラス宣言・実装
- クラスはヘッダファイル
*.hと実装ファイル*.mで定義。ファイル名がクラス名。クラス名は大文字始まり。- ヘッダファイルの
@interfaceから@endの間にクラスのメンバ等を定義@propertyでメンバ変数の定義。いろいろなオプションある。@propertyプロパティで宣言するとアクセサを勝手に定義してくれる。デフォルトはprotected。- メソッドの定義は
-始まりならインスタンスメソッド、+始まりならクラスメソッド。メソッド名は小文字始まり。
- 実装は実装ファイルの
@implementationから@endの間に - 実装ファイルの先頭で
@interface クラス名()から@endと書かれてる部分はクラスエクステンション- クラスエクステンションの中でメンバを宣言するとprivate的な扱い
- ヘッダファイルの
- 継承はヘッダファイルでクラス名の後に
:で宣言する。単一継承。@interface ChildClass : ParentClass
- protocolというJavaのInterface的なもの(
@optionalによって実装しないでも良いメソッドも定義できるのが異なる) を定義することでまとまった機能を継承できる- 宣言は
@protocolプロパティ - 継承する時は親クラス名の後に
<>内に記述。複数継承する場合はカンマ区切り。@interface ChildClass : ParentClass <FooProtocol, BarProtocol>
- 宣言は
メソッド定義・呼び出し
Objective-Cで一番なれなかったのはメソッド呼び出し(メッセージ式)でした。メソッド見ても最初「なんのこっちゃ?」という感じだったので。
- メソッド定義は次の通り
- -/+ (戻り値型)メソッド名部分1:(引数1型)引数1 メソッド名部分2:(引数2型)引数2
- メソッド名は引数を除いた部分を全部つなげたもの
- メソッド名部分1:メソッド名部分2: がメソッド名(最後のコロンも入る)
- へんてこりんに見えるけど、英語で書くとなんか自然言語っぽくなる
- たいていメソッド名は verb:noun/adv/adj:noun/adv/adj... という感じで続く
- eg1.
- (NSInteger)countNSInteger型を返すcountメソッド(引数が無い)
- eg2.
- (Image *)initWithFile:(NSString *)path Title:(NSString *)title Description:(NSString *)descImage *型を返すinitWithFile:Title:Decription:メソッド(引数は全部NSString型の引数pathとtitleとdesc)
- メソッド呼び出しは
[ ... ]で行う(メッセージ式)- eg1.
[someString count]; - eg2.
[[Image alloc] initWithFile:@"hoge.jpg" Title:@"great pic" Description:@"flower"];
- eg1.
UI作成
StoryboardやらInterface Builderやらを使えばポトペタで楽ちんなんだろうけど、いろいろ隠蔽されまくるので、最初はなるべくコードで書きながら理解した。このへんのドキュメントを読むとわりと理解できた。
ViewとかViewControllerとか
まあMVCやってますよという話
- Viewはデータを表示する箱
- ButtonもWebViewもCanvasも全部Viewです
- Viewの上下関係に気をつけましょう
- ViewをView Controllerの中にまとめて画面を構成する
- View Contollerが画面を構成する単位
- コンテンツを表示するContent View Controller
- 画面の遷移情報を管理するNavigation Controller
- データ情報を管理するContainer View Controller
- iOSではTableを使ったUIが非常に多いのでTableViewControllerっていうのがあるよ
- まあ普通にViewController定義してTableViewを持ってるのと変わらないけど、はじめからいろいろ定義してあって便利
- コンポーネント間のやり取りはprotocolとdelegateを使って行う
- eg1. ViewController内のView(ボタンとか)のコールバックを受け取るためにViewControllerが自分自身をdelegate
- eg2. 遷移先のViewControllerからの結果を遷移元が受け取るために、遷移先のprotocolを遷移元が実装して、遷移元が自分自身をそのprotocolのdelegate先とする
全部コードで書く場合に意識すること
- ViewControllerの
loadViewやviewDidLoad内で初期化 initWithNibNameとか用なしなので自分でinit***を書く- イベントはことごとく次のようなメソッドを定義して受け取る
- (IBAction)didSomething:(id)sender
snippet
initWith***系
- (id)initWithTitle:(NSString *)title { self = [super init]; if (self) { self.title = title; } return self; }
AppDelegate初期化
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; // Override point for customization after application launch. Hoge *hoge = [[Hoge alloc] initWithString:@"hoge"]; FooViewController *foo = [[FooViewController alloc] initWithHoge:hoge]; UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:foo]; self.window.rootViewController = nav; [self.window makeKeyAndVisible]; return YES; }
アプリケーションのルートとNavigation Controllerのルートは別だっていうのは、1回アプリ作っちゃえばわかるんだけど、最初はRootViewControllerって言葉が2回出てきてすごく混乱した。
ところで
はてなブログでObjective-Cのsyntax highlight用キーワード調べるのに苦労した。 objc でいいんですね。