Hatena::ブログ(Diary)

h.INALOG RSSフィード

2010-08-31 メソッド,セレクタ,メソッドの実装

no title

を激しく参考にさせていただいています.

[]メソッド 09:09 メソッドを含むブックマーク

メソッドはMethod型で定義され,ランタイムAPIを以下のように追いかけていくと,

@objc-class.h

typedef struct class-method *Method

同じく@objc-class.h

struct class-method {
    SEL method_name;
    char *method_types;
    IMP method_imp;
}

となってて,

で構成される構造体にたどり着く.

[]セレクタ 09:09 セレクタを含むブックマーク

セレクタはSEL型の変数で表現されてて,objc.hで,

typedef struct objc_selector *SEL;

と定義されている.

objc_selector構造体の定義はなく,Opaque構造体というらしい.

[]メソッドの実装 09:09 メソッドの実装を含むブックマーク

メソッドの実装は実際の実装部分へのポインタで表現されてて,IMP型の変数になってる.

IMP型はobjc.hで,

typedef id (*IMP)(id, SEL, ...);

と定義される関数ポインタ

可変長引数で,id型の第一引数,SEL型の第二引数をとり,id型の返り値を返す.

2010-08-30 クラス

[]クラス 12:10 クラスを含むブックマーク

クラスはClass型で定義されるが,そのClass型はobjc.hで

typedef struct objc_class *Class; 

と定義されている.さらに構造体objc_classはobjc-class.hで,

struct objc_class
{
    struct objc_class* isa;
    struct objc_class* super_class;
    const char* name;
    long version;
    long info;
    long instance_size;
    struct objc_ivar_list* ivars;
    struct objc_method_list** methodLists;
    struct objc_cache* cache;
    struct objc_protocol_list* protocols;
};

と定義されている.これがクラスの実態.

  • isa
    • メタクラスへのポインタ.メタクラスのisaにはNSObjectメタクラスへのポインタが入ってて,NSObjectメタクラスのisaにはNSObjectクラスが入ってる.ちなみにid型で定義されるオブジェクトもisaフィールドをもってて,クラスへのポインタが入ってる(id型はobjc-api.hで『typedef struct objc_object { class isa; } *id;』と定義されている) .
  • super_class
  • name
    • クラスの名前.C文字列.
  • version
    • クラスのバージョン番号.実行時,class_setVersion関数で変更できる.コンパイラは最初 0 として定義する.
  • info
    • ランタイム関数によって使われる一連のビットフラグが格納されている.
      • CLS_CLASS (0x1L):このクラス定義がクラスを表しており,そのクラスの新しいインスタンスごとに割り当てられるインスタンスメソッドと変数定義が含まれていることを示す.
      • CLS_META (0x2L):このクラス定義がメタクラスを表しており,そのクラスのいずれかのインスタンスに固有のものではないメソッドのリスト(クラスメソッド)が含まれていることを示す.
      • CLS_INITIALIZED (0x4L):ランタイムによってこのクラスが初期化されたことを示す.このフラグをセットできるのはobjc_addClass関数のみ.
      • CLS_POSING (0x8L):このクラスが別のクラスになりすましていることを示す.
      • CLS_MAPPED (0x10L):Objective-C ランタイムによって内部的に使用される.
      • CLS_FLUSH_CACHE (0x20L):Objective-C ランタイムによって内部的に使用される.
      • CLS_GROW_CACHE (0x40L):Objective-C ランタイムによって内部的に使用される.
      • CLS_NEED_BIND (0x80L):Objective-C ランタイムによって内部的に使用される.
      • CLS_METHOD_ARRAY (0x100L):methodListsフィールドが単一のobjc_method_listデータ構造体へのポインタではなく,objc_method_listデータ構造体のポインタの配列であることを示す.
  • instance_size
  • ivars
  • methodLists
    • CLS_METHOD_ARRAYフラグがセットされている場合,このクラスのインスタンスであるオブジェクトに送信できるすべてのインスタンスメソッドを一括で指定したobjc_method_listデータ構造体の配列になる.CLS_METHOD_ARRAYフラグがセットされていない場合,単一のobjc_method_listデータ構造体へのポインタ.このクラスがメタクラス定義である場合は,そのクラスのクラスメソッドを指定している.
  • cache
    • objc_cacheメソッドキャッシュデータ構造体へのポインタ。
  • protocols
    • objc_protocol_listデータ構造体へのポインタ.このクラスが実装しているとされる正式なプロトコルのリスト.

[]クラスの書き方 12:54 クラスの書き方を含むブックマーク

クラスは通常インターフェース部と実装部を別々のファイルに記述する.

インターフェース拡張子.hのインターフェースファイルに記述する.

実装部は拡張子.mの実装ファイルに記述する.

ひとつのファイルに複数のクラスを記述することが可能であるが,通例として1ファイル/1クラスとし,ファイル名は通常,記述されているクラス名と同じにする.

ルートクラスはNSObjectで,あらゆるクラスはNSObjectを根にもつ木構造にぶらさがる感じになっている.

インターフェース

↓こんな感じで書く

@interface Class:SuperClass
{
 var;
 ・・・
}
method
・・・
@end

クラス名は大文字から,変数,メソッド名は小文字からはじめるのが通例.

インターフェースファイルのインポート

↓こんな感じで記述する.

#import "Rectangle.h"

Objective-Cでは#includeの代わりに主に#importを使う.多重呼び出しを防いでくれる.

スーパークラスインポートすることで,NSObjectからそのスーパークラスまですべての派生クラスの宣言を暗黙のうちに含む.

インターフェイスがその階層以外のクラスを記述している場合は,それらを明示的にインポートするか,@classディレクティブで宣言する必要がある.

インターフェースファイルの役割

インスタンス変数は,インターフェイスファイルで宣言する必要がある.

コンパイラオブジェクトが定義されている場所だけでなく,オブジェクトが使用される場所でもオブジェクトの構造を認識している必要があるから.

クラスの実装

↓こんな感じで書く.

@implement Class:SuperClass
{
 var;
}
method
@end

すべての実装ファイルは,自身のインターフェースファイルをインポートしなければならない.

変数宣言とスーパークラス名は省略可.

インスタンス変数のスコープ

インスタンスの生成

インスタンスはクラスにallocメソッドを送って生成する.

[class alloc];

allocメソッドで生成した段階では,メモリの領域が確保されるだけで実体はない.

主にinitまたはinitではじまるイニシャライズ用メソッドにより実体が生成される.

[[class alloc] init];

[]クラスオブジェクト 12:10 クラスオブジェクトを含むブックマーク

クラスはインスタンス化するまで実体がないんだけど,その実体のないクラスもオブジェクトとして考えましょうということ.

変数,メソッドはインスタンス化してから使用可能になるのが通常だけど,インスタンス化しなくても使用可能な変数,メソッドもある(クラス変数,クラスメソッド).

#ちなみにObjective-Cにはクラス変数みたいなものはない.

allocメソッドなんか,まさにクラスメソッド.NSObjectで定義されてる.

クラスオブジェクトの型

オブジェクトはid型で表すことができるが,クラスオブジェクトには特にClass型という型が用意されている.

クラスメソッド

定義は↓こんな感じで.

@interface Class1 : Class0
- (型)インスタンスメソッド
+ (型)クラスメソッド
@end

クラス変数

Objective-Cにはクラス変数という定義のものは存在しないが,static指定子とともに定義された変数をクラス変数の代用として利用可能.

とはいえstaticな変数に直接アクセスすることはできなくて,setter/getterをクラスメソッドにしてアクセスするという使い方になる.

クラスオブジェクト初期化

initializeメソッドをオーバーライドする.


[]真理値表 12:56 真理値表を含むブックマーク

論理回路における入力と出力の関係を記述した表.

(例)論理和(OR)の真理値表

入力A入力B出力Z
000
011
101
111

[]基本的な論理関数 12:56 基本的な論理関数を含むブックマーク

OR:論理和

Z=A+B

f:id:inadome:20100830124318j:image

f:id:inadome:20100830124646j:image

入力A入力B出力Z
000
011
101
111

AND:論理積

Z=A¥cdot B

f:id:inadome:20100830124813j:image

f:id:inadome:20100830124909j:image

入力A入力B出力Z
000
010
100
111

NOT:否定

Z=¥overline{A}

f:id:inadome:20100830125520j:image

f:id:inadome:20100830125604j:image

入力A出力Z
01
10

2008-05-11

[][][]NSObject使う 20:59 NSObject使うを含むブックマーク

calc.h

#import <Foundation/NSObject.h>

@interface calc:NSObject
-(int) plus:(int)x y:(int)y;
@end

calc.m

#import "calc.h"

@implementation calc
-(int) plus:(int)x y:(int)y
{
    return x+y;
}
@end

main.m

#import <Foundation/Foundation.h>
#import <stdio.h>
#import "calc.m"

int main(void)
{
        id arp = [[NSAutoreleasePool alloc] init];

        int x=10;
        int y=20;

        id cal = [calc alloc];
        [cal autorelease];

        int ans = [cal plus:x y:y];

        printf("x = %d\ny = %d\nx + y = %d\n", x,y,ans);

        [arp release];
}

$gcc main.m -framework Foundation && ./a.out
x = 10
y = 20
x + y = 30
$

2008-04-30

[][][]Objective-Cを学ぶ 21:23 Objective-Cを学ぶを含むブックマーク

hello world

#import <stdio.h>

int main(void){
    printf("hello world\n");
    return 0;
}

includeがimportに変わってるだけ

$ gcc helloworld.m && ./a.out
hello world
$

拡張子が.mになってるだけ


NSLog

#import <stdio.h>
#import <Foundation/Foundation.h>

int main(void){
    printf("hello world\n");
    NSLog(@"\nhello!hello!!");
    return 0;
}
$ gcc -framework Foundation helloworld.m && ./a.out
hello world
2008-05-01 02:49:56.315 a.out[530:10b] 
hello!hello!!
$ 

2008-04-10