Cocoa Pro5

Post on 28-Jun-2015

971 views 0 download

Tags:

Transcript of Cocoa Pro5

iPhone輪講Lesson10/Lesson11

乗るしかないこのビッグウエーブに

第5回

Lesson10Objective-Cの文法

クラスの宣言と実装

クラスの記述は2つの部分からなるクラスの宣言

クラスがどういったインスタンス変数を持っているか,どういったメソッドを持っているかということを定義するする部分

クラスの実装

宣言したメソッドの定義を書く部分

クラスの宣言と実装

クラスの宣言と実装のファイルにはそれぞれ拡張子があるクラス宣言には「.h」という拡張子をつける

hはヘッダ(header)の意味

クラス実装には「.m」という拡張子をつける

mはメソッド(method)の意味

文法実験の仕方

以前作ったObjective-CのテストのためのプロジェクトObjC Testをひらくソースコードは3つのファイルに書かれていた

クラス宣言のためのファイルはMyObject.h

クラス実装のためのファイルはMyObject.m

クラスをインスタンス化してメソッドを呼び起こすのがObjC Test.m

文法実験の仕方

ObjC Test.mのソースコードを見返してみる

文法実験の仕方

ObjC Test.mのソースコードを見返してみる

文法実験の仕方

ObjC Test.mのソースコードを見返してみるNSAutoreleasePoolというクラスのインスタンス化を行っている

文法実験の仕方

ObjC Test.mのソースコードを見返してみる

文法実験の仕方

ObjC Test.mのソースコードを見返してみる

文法実験の仕方

ObjC Test.mのソースコードを見返してみる

文法実験の仕方

ObjC Test.mのソースコードを見返してみる

MyObjectクラスのインスタンス化をしている

クラスの宣言

クラス宣言の読み込みクラスは親クラスを継承してサブクラスを作る

ソースコードを読み込んで処理するのはコンパイラ

コンパイラが親クラスの事を知らなくてはいけない

コンパイルするとき,親クラスの宣言を読み込んでおく

フレームワークのクラス宣言の読み込み

読み込むために使うのが「#import」という文Cocoaのクラス宣言ファイルを読み込むには,以下のように書く

これは「システムにある,Cocoaフレームワークの,Cocoa.hというファイルを読み込む」という意味

#importの後の< >が,システムのヘッダファイルを意味する

フレームワークのクラス宣言の読み込み

#import <Cocoa/Cocoa.h>の指示で読み込むファイル/システム/ライブラリ/Frameworks/Cocoa.framework/Headers/Cocoa.h

Foundation,AppKit,CoreDataというフレームワークのヘッダファイルを読み込んでいる

自分で作ったクラス宣言の読み込み

自分で作ったクラス宣言ファイル(Tigers.h)を読む場合は以下のように書く

#importの後にダブルクォーテーション(“ “)が来ている

これはヘッダファイルがプロジェクト内部にある事を示す

クラスの宣言

クラスの宣言をするまず名前を決める(今回はMyObject)

親クラスを決める

何かのクラスを拡張するときは,そのクラスを書く

何も無い場合はCocoaのルートクラスのNSObjectを使う

クラス宣言の宣言 クラス名 親クラスの名前

インスタンス変数の宣言

クラスの宣言にインスタンス変数の宣言を加える事ができる

@interfaceと@endの間に「{ }」を加えて,その中に書く

メソッドの宣言

引数なしのインスタンスメソッドインスタンス変数であるcountの値を取得するためのメソッドを宣言する

文法は  - (返り値型)メソッド名;

メソッドの宣言

引数1つのインスタンスメソッドcountの値を設定するためのメソッド

文法は - (返り値型)メソッド名:(引数型)引数名;

メソッドの宣言

引数2つ以上のインスタンスメソッドcountとindexの値を同時に設定する

文法は - (返り値型)メソッド名:(引数名)引数名 ラベル:(引数型)引数名;

メソッドの宣言

クラスメソッドメソッドにはクラスメソッドもある

インスタンスメソッドの宣言は「 - 」から始まっていたが,クラスメソッドの宣言は「 + 」から始まる

それ以外はインスタンスメソッドと同じ

クラスの実装

クラスの実装を書いてみるクラスの実装には@implementationを使う

@implementationの後ろにはクラス名が来る

メソッドの実装

MyObjectにメソッドの実装を付け加える

メソッドの実装は@implementationと@endの間に書く

宣言と同じ形でメソッドを書き,中括弧({ })の中にメソッドでの処理を実装していく

メソッドの宣言は常に必要か?

ここまでだと「.hでメソッド宣言」→「.mでメソッド実装」という流れメソッドの宣言は常に必要なのか?

Objective-Cでは,メソッドの宣言をせずに,いきなり実装しても構わない

他のクラスから呼んでもらう必要の無いものは.hファイルに加えなくてよい

オブジェクトのための変数型

Objective-CはC言語ベースなので,基本的な変数の型はC言語と同じchar,int,floatといった型はそのまま使える

それらに加えて,Objective-Cのための変数も追加されている

それがオブジェクトのための変数型

インスタンスオブジェクトのための変数型

インスタンスオブジェクトのための変数クラスをインスタンス化するとオブジェクトができる

このオブジェクトに入れるための変数

インスタンスオブジェクトのための変数型

変数は「クラス名のポインタ」という形式の型になるMyObjectクラスのインスタンスのための変数

CocoaのクラスであるNSStringのための変数

id型

オブジェクトの変数のための型にはid型という特殊なものが用意されているid型はすべてのオブジェクトのために使える型

CocoaのすべてのクラスはNSObjectから継承されている

このNSObjectにはObjective-Cのすべてのオブジェクトに共通するデータが含まれている

これを表すための変数型がid型

id型

すべてのオブジェクトはid型の変数に代入することができるそれだと,その変数が何のクラスだったのかわかりにくい

それを避けたいときはクラス名のポインタ型を使うことになる

id型

以前作ったHello WorldアプリケーションのAppController.hを開くクラスの宣言でid型が使われていた

何のクラスかわかりやすく書き換える

nil値

C言語ではポインタが何も指してない状態を表すためにNULLという値があったObjective-Cにもオブジェクトのための変数が,何のオブジェクトも指し示していないことを表すnilという値がある

これでstringという変数は何も指し示していないという事が保証される

メソッドの呼び出し

インスタンスメソッドの呼び出しMyObjectクラスにcountというクラスを実装した

これを呼び出してみる

インスタンスメソッドを呼び出すには,あらかじめインスタンス化しておかなければならない →Lesson12

メソッドの呼び出し

インスタンスメソッドの呼び出しインスタンス化されたオブジェクトに対して,メソッドを呼び出しているのが「count = [object count];」

文法は 返り値 = [インスタンス メソッド名];

メソッドは関数と同じように返り値を返す.

角括弧の中にインスタンスオブジェクト,空白をあけてメソッド名を書く

これがメソッドの呼び出し

クラスメソッドの呼び出し

クラスメソッドの呼び出し文法自体はインスタンスメソッドのものと変わらない

違いは呼び出しの対象となるオブジェクト

インスタンスメソッドのときは,インスタンス化したオブジェクトを使った

クラスメソッドは,クラス全体に対して呼び出す

呼び出す対象のところにクラス名を指定する

オブジェクトがnilの場合

インスタンスメソッドの呼び出しのとき,インスタンスのオブジェクトのための変数を使っていた普通にインスタンス化されたオブジェクトを指していれば問題無し

nilが入っていた場合どうなるか

nilに対してメソッドを呼び出すと,その呼び出しは無視される

返り値は型に関わらず0が返ってくる

Lesson11チュートリアル:RSSリーダ

開発の手順

1. 新規プロジェクトの作成をするCocoa Applicationテンプレートを使う

2. アプリケーションのためのクラスを作成をするMVCアーキテクチャに則って,コントローラを1つ作る

アウトレットとアクションも追加しておく

開発の手順

3. Interface Builderでユーザインタフェースのデザインをするインタフェースの部品に様々な設定を施す

4. アウトレットとアクションを接続するアウトレットはコントロールクラスから,アクションはボタンとテキストフィールドから接続する

テーブルビューでは特殊な設定が必要となる

開発の手順

5. ソースコードを書く

6. ビルドしてから実行する

プロジェクトの作成

プロジェクトを作成する[ファイル]→[新規プロジェクト...]メニューを開く

「Cocoa Application」を選択する

プロジェクト名は「RSS Reader」にして適当な場所に保存

プロジェクトの作成

ガベージコレクションの設定プロジェクトウィンドウのターゲットの項目を開く

「RSS Reader」という名前のターゲットがあるのでダブルクリック

「ターゲット”RSS Reader”の情報」というウィンドウが開く

プロジェクトの作成

ガベージコレクションの設定

「ターゲット”RSS Reader”の情報」のウィンドウにはタブがあるので「ビルド」のタブを選択

ビルドの設定を行う画面になる

構成のメニューは「すべての構成」,表示のメニューは「すべての設定」にしておく

プロジェクトの作成

ガベージコレクションの設定

「GCC 4.0 - Code Generation」のカテゴリの中にある「Objective-C Garbage Collection」の設定を変更する

ガーベッジコレクションの設定では「Unsupported」「Supported」「Required」という値を指定できる

ここでは「Required」を指定する

クラスの作成

クラスを作成するアプリケーションのためのコントローラクラスを作る

[ファイル]→[新規ファイル...]メニューを選択する

テンプレート一覧から「Objective-C class」を選択する

ファイル名を「AppController」とする

クラスの作成

AppController.hを編集する

ユーザインタフェースのデザイン

部品の配置プロジェクトウィンドウでMainMenu.xibを開く

Interface Builderが起動するのでそちらで作業する

アプリケーションのメインウィンドウが開いているので,その上に部品を配置していく

ユーザインタフェースのデザイン

部品の配置今回使う部品は4種類

1.編集可能なテキストフィールド

2.編集不可能なテキストフィールド

3.ボタン

4.テーブルビュー

ユーザインタフェースのデザイン

部品の配置部品はライブラリの[Cocoa]→[Views&Cells]の下にある

テキストフィールドは[Inputs&Values]

ボタンは[Buttons]

テーブルビューは[Data Views]

ユーザインタフェースのデザイン

ユーザインタフェースをデザインするウィンドウ上に部品を配置していく(全部で8ヶ所)

① ② ③ ① ①①

④ ⑤⑥ ⑦

ユーザインタフェースのデザイン

テキストフィールドの設定編集可能なテキストフィールドを選択する

インスペクタパネルのAttributesタブの「Action」と書かれているポップアップメニューから「Set On Enter Only」を選択する

Enterキーを押したときにだけアクションが送られるようになる

ユーザインタフェースのデザイン

テキストフィールドの設定編集可能なテキストフィールドを選択する

インスペクタパネルのAttributesタブの「Action」と書かれているポップアップメニューから「Set On Enter Only」を選択する

Enterキーを押したときにだけアクションが送られるようになる

ユーザインタフェースのデザイン

テキストフィールドの設定編集可能なテキストフィールドを選択する

インスペクタパネルのAttributesタブの「Action」と書かれているポップアップメニューから「Set On Enter Only」を選択する

Enterキーを押したときにだけアクションが送られるようになる

ユーザインタフェースのデザイン

テーブルビューの設定テーブルビューをクリックする

インスペクタのタイトルバーに「Scroll View」と表示されていれば,テーブルビューの外側に位置するスクロールビューを選択していることになる

ユーザインタフェースのデザイン

テーブルビューの設定

スクロールビューが選択されている状態で設定を行う

横スクロールバーを表示しないようにする

インスペクタのAttributesタブにある「Show Horizontal Scroller」のチェックを外す

ユーザインタフェースのデザイン

テーブルビューの設定Scroll Viewの状態でテーブルをもう一度クリックする

インスペクタのタイトルが「Table View」になる

スクロールビュー内部のテーブルビューが選択できている事を示している

ユーザインタフェースのデザイン

テーブルビューの設定

「Col. Sizing」というポップアップメニューから「Uniform」を選択する

これでテーブルビューの大きさを変更したとき,列サイズも均等に変わる事になる

ユーザインタフェースのデザイン

テーブルビューの設定テーブルのヘッダ部分をクリックする

タイトルが「Table Header View」となる

さらにクリックして,ヘッダのみが白く強調され他がグレーアウトになるようにする

この状態で列の境目をドラッグして,列の大きさが調整できる

ユーザインタフェースのデザイン

テーブルビューの設定ヘッダをダブルクリックする事で 列にタイトルを設定できる

左側に「Title」右側に「Link」を入力する

ユーザインタフェースのデザイン

テーブルビューの設定列の識別子を設定する

「Table Column」と呼ばれる項目を選択する必要がある

再び「Table View」を選択した状態にする

この状態でテーブルビューの左側の領域をクリック

左側だけが強調されて,インスペクタのタイトルが「Table Column」となる

ユーザインタフェースのデザイン

テーブルビューの設定

識別子の設定をする

インスペクタに「Identifier」という項目がある

Title列は「title」,Link列には「link」と入力する

「Editable」のチェックをそれぞれ外す

自動リサイズの設定

自動リサイズの設定をするURLテキストフィールドの設定をおこなう

「URL:」と書いてあるテキストフィールドを選択してインスペクタのSizeタブも表示する

このテキストフィールドは左上に固定する

Autosizingの設定で外側の左と上の設定をする

自動リサイズの設定

同様にすべての部品を設定する「Title:」,「Link:」のテキストフィールドは左上固定

編集可能なテキストフィールド,「title」,「link」のテキストフィールドは上に固定で横方向にはリサイズ

「Read」ボタンは右上固定

テーブルビューはスクロールビューの中に入れられている

リサイズの設定は外側のスクロールビューに対しておこなう

自動リサイズの設定

ウィンドウの設定

ウィンドウのタイトルを設定するウィンドウを選択して,インスペクタのAttributesのタブを表示する

「Title」というテキストフィールドに,「RSS Reader」と入力する

クラスのインスタンス化

クラスをインスタンス化するライブラリの[Cocoa] > [Objects&Controller] > [Controllers]にあるObjectをxibウィンドウにドラッグして追加

オブジェクトを選択したままインスペクタを表示し,Identityタブで「AppController」クラスを選択する

アウトレットとアクションの接続

テキストフィールドのアウトレットを接続する

「urlTextField」,「titleTextField」,「linkTextField」をコントロールキーを押しながらそれぞれ接続する

urlTextFieldtitleTextField

linkTextField

アウトレットとアクションの接続

アクションの接続をする

「Read」ボタンから,「readURL;」アクションに接続する

入力可能なテキストフィールドからも「readURL ;」アクションに接続する

このアクションはテキストフィールドで Enterキーを押したときに送られる

readURL; readURL;

アウトレットとアクションの接続

テーブルビューのアウトレットを接続する

コントロールをしながらテーブルビューをクリックし,AppControllerまでドラッグして,上でドロップする

テーブルビューアウトレットの中から「dataSource」を選択

dataSource

AppControllerクラスの実装

AppController.mを編集するソースコードの内容は次のスライドから…

#import "AppController.h"

@implementation AppController

- (IBAction)readURL:(id)sender{ NSURL* url; url = [NSURL URLWithString:[urlTextField stringValue]]; // XMLドキュメントを作成します document = [[NSXMLDocument alloc] initWithContentsOfURL:url options:0 error:NULL]; if (!document) { return; } // '/rss/channle/title'のノードを取得します NSArray* nodes; nodes = [document nodesForXPath:@"/rss/channel/title" error:NULL]; if ([nodes count] == 0) { // '/rdf:RDF/channel/title'のノードを取得します nodes = [document nodesForXPath:@"/rdf:RDF/channel/title" error:NULL]; } if ([nodes count] == 0) { // '/feed/title'のノードを取得します nodes = [document nodesForXPath:@"/feed/title" error:NULL]; }

if ([nodes count] == 1) { NSXMLNode* titleNode; titleNode = [nodes objectAtIndex:0]; // テキストフィールドにタイトルを設定します NSString* title; title = [titleNode stringValue]; [titleTextField setStringValue:title]; } // '/rss/channle/link'のノードを取得します nodes = [document nodesForXPath:@"/rss/channel/link" error:NULL]; if ([nodes count] == 0) { // '/rdf:RDF/channel/link'のノードを取得します nodes = [document nodesForXPath:@"/rdf:RDF/channel/link" error:NULL]; } if ([nodes count] == 0) { // '/feed/link'のノードを取得します nodes = [document nodesForXPath:@"/feed/link" error:NULL]; }

if ([nodes count] == 1) { NSXMLNode* linkNode; linkNode = [nodes objectAtIndex:0]; // テキストフィールドにリンクを設定します NSString* link; link = [linkNode stringValue]; [linkTextField setStringValue:link]; } // テーブルビューにデータを読み込みます [tableView reloadData];}

// NSTableViewデータソース- (int)numberOfRowsInTableView:(NSTableView*)tableView{ if (!document) { return 0; }

// '/rss/channel/item/'のノードを取得します NSArray* nodes; nodes = [document nodesForXPath:@"/rss/channel/item" error:NULL]; if ([nodes count] == 0) { // '/rdf:RDF/item'のノードを取得します nodes = [document nodesForXPath:@"/rdf:RDF/item" error:NULL]; } if ([nodes count] == 0) { // '/feed/entry'のノードを取得します nodes = [document nodesForXPath:@"/feed/entry" error:NULL]; } // ノードの数を返します return [nodes count];}

// NSTableViewデータソース- (id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)tableColumn row:(int)row{ if (!document) { return nil; } // テーブルカラムの識別子を取得します id identifier; identifier = [tableColumn identifier]; // '/rss/channel/item/'のノードを取得します NSArray* nodes; nodes = [document nodesForXPath:@"/rss/channel/item" error:NULL]; if ([nodes count] == 0) { // '/rdf:RDF/item'のノードを取得します nodes = [document nodesForXPath:@"/rdf:RDF/item" error:NULL]; } if ([nodes count] == 0) { // '/feed/entry'のノードを取得します nodes = [document nodesForXPath:@"/feed/entry" error:NULL]; }

// 指定された行の、ノードを取得します NSXMLNode* node; node = [nodes objectAtIndex:row]; if ([identifier isEqual:@"title"]) { // 'title'の文字列を取得します nodes = [node nodesForXPath:@"title" error:NULL]; if ([nodes count] == 1) { node = [nodes objectAtIndex:0]; return [node stringValue]; } } if ([identifier isEqual:@"link"]) { // 'link'の文字列を取得します nodes = [node nodesForXPath:@"link" error:NULL]; if ([nodes count] == 1) { node = [nodes objectAtIndex:0]; return [node stringValue]; } } return nil;}

@end

ビルドと実行

ビルドして実行する

[ビルド]→[ビルドと実行]メニューを選択する

RSS Readerのアプリケーションが起動する

おわり