第5回
iPhone輪講
Lesson10/Lesson11
 乗るしかないこのビッグウエーブに
Lesson10
Objective-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のソースコードを見返してみる
文法実験の仕方

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

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」クラスを選択する
アウトレットとアクションの
      接続

テキストフィールドの             titleTextField

アウトレットを接続す                              urlTextField
                    linkTextField
る

「urlTextField」,
「titleTextField」,
「linkTextField」を
コントロールキーを押しな
がらそれぞれ接続する
アウトレットとアクションの
      接続
アクションの接続をする

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


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

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

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

コントロールをしながらテーブル
ビューをクリック
し,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のアプリケーションが
 起動する
おわり

Cocoa Pro5