Category Archive: iPhone

[iPhone] Objective- Cの勉強メモ:カテゴリという概念を使って元クラスの拡張(メソッドの追加)できる

Objective-CにはASにはない機能でカテゴリという概念がある。
これはクラスファイルにメソッドを追加することができる機能。

通常クラスを拡張するにはそのクラスを継承したサブクラスを定義すればいいと思う。
でも根本的に弄りたくなった場合、元のクラスを書き換えちゃうということもできる。
(ASだと、Flash8でAS2のときは直接編集できたけど、AS3ではSWCになってるから無理ぽ)
でも書き換えちゃうと何か不具合がおきたときとかバックアップとってないと元に戻すのが大変。

というわけでカテゴリという概念は、元クラスを簡易的に拡張できるという概念。
ただし追加できるのはメソッドだけ。
変数は追加できない。
手順は拡張用のクラス(?)ファイルを作ってそこで定義する。

例)UIViewを拡張する、UIViewExファイルを生成する場合
//ヘッダーファイル


#import <UIKit/UIKit.h>
//ここでの()の中の名前は任意(ファイル名と同じでなくてよい)
@interface UIView (AnimationExtension)
//メソッドの定義
//ここに追加したいメソッドを書く
-(void) hoge;
@end

//実行ファイル


#import "UIViewExtention.h"
@implementation UIView(AnimationExtension)
//メソッドの実装
    //ここで定義したメソッドを実装する
 -(void) hoge{
    //処理
}
@end

書き方で注意するのは、ヘッダーファイルでのinterfaceのくだり。
変数は定義できないので、{}は書く必要なし。

これを反映されるには、反映させたいクラスファイルにて


#import "UIViewExtention.h"

を記述すればよい。
これが記述されたクラス内では、UIViewインスタンスにUIViewExで追加したメソッドが普通に使えるようになる。

//例


-(void) init{
//imageViewはUIImageVIewクラスのインスタンス
//(UIImageViewのスーパークラスはUIImageなのでhogeメソッドが使える)
[imageView hoge];
}

[iPhone]Objective- Cの勉強メモ:乱数の取り扱い

まずはObjective-CというかC言語での乱数の発生させる方法。
使える関数は2種類
まず
int rand(void);
という関数でint型の乱数を返すことができる。
このときに返る値は、0~馬鹿でかい数という感じ。
馬鹿でかい数はコンパイラによって変わるらしい。
(ASのMath.random()のように、0~1未満というわけでない)


int i;
i = rand();
printf(%d,i);//0から馬鹿でかい数の間の間

ただ、このままだと乱数は実行するたびに常に同じ値を返すことになるので、初期化処理という行為が必要になる。
そこで使うのがsrand();
void srand(unsigned int 初期値);

使い方としては、rand()関数を実行する前にsrand()関数を実行することで初期化すればよし。
初期値には、絶対にかぶらない値を日付データから取ればよし。


//time(NULL)で現在の時刻が1970年1月1日午前0時0分0秒からの通算秒数で得られる。
srand(time(NULL));
rand();

以上が、C言語での設定方法

Objective-Cではsrandは以下のようにするらしい。


//NSDateインスタンスを作って、本日の日付けを秒数に換算してる
srand([[NSDate date] timeIntervalSinceReferenceDate]);
rand()

※C言語のやり方でも問題なさげ。

[iPhone]Objective- Cの勉強メモ:プロパティ宣言:@propertyの意味

ヘッダーファイルにて、プロパティ宣言をすることでそのプロパティについてのゲッターセッターが実装される。
プロパティ宣言をしなくても、自分で実装処理を書いてもよい

プロパティの書式は、


//ヘッダーファイルに書く
//@property (属性 , 属性, ・・・) データ型, 名前
//例
@property ( nonatomic, retain ) NSTimeZone* timeZone;

//ソースファイルに書く
@synthesize timeZone;

上の例を自分で実装した場合は


//ソースファイルに書く
//ゲッター
-(NSTimeZone*) timeZone{
//同時実行不可のための処理:属性nonatomicに相当
@synchronized(self){
return timeZone;
}
}
//セッター:読み書きについて属性が未設定なのでセッターまで生成される
-(void) setTimeZone:(NSTimeZone *)zone{
//同時実行不可のための処理:属性nonatomicに相当
@synchronized(self){
if(timeZone != zone){
[timeZone release];
timeZone = [zone retain];//保持する際は保持カウントをアップさせる:属性retainに相当
}
}
}

※@synchronizedは排他制御するかしないか。
マルチスレッドで同時に実行して欲しくない処理があるとき、これを指定することで片方のスレッドを停止することができる。
上の例では排他制御に対応しており、プロパティの属性でnonatomicを指定すると、排他制御はしなくなる。

[iPhone]Objective-Cの勉強メモ:dealloc

クラスファイルの最後の方にやたら登場するdeallocメソッド
NSObjectのメソッドで、それをオーバーライドしている。
dealloc実行のタイミングは保持カウントが0になったときに実行される。

保持カウントはインスタンスの生成、retainさせた参照の追加でカウントアップ。
releaseでカウントダウンされるのでカウント数には注意が必要。

例)


- (void)dealloc {
    [window release];
//スーパークラス(NSObject)のdeallocを実行することで実際のメモリの破棄
//C言語のfree関数のようなもの
    [super dealloc];
}

[iPhone]Objective-Cの勉強メモ(ActionScriptとの比較的な):プロトコル

Objective-Cにはプロトコルという概念がある。
ActionScriptでいうところのInterfaceみたいなものらしい。
記述はヘッダーファイルでのクラスの定義のところに書く


@interface クラス名 : スーパークラス名 <プロトコル名>
//例
@interface ClockAppDelegate : NSObject <UIApplicati> {

プロトコルはデリゲートとも関わりがある。
たとえば、あるAクラスのデリゲート対象とされたBクラスはAクラスのプロトコルを記述しないとWarningになる。


//例)
//UIWebViewクラスのインスタンス(webView)が現在のクラス(self)にデリゲートされてる
webView.delegate = self;
//このwebViewを持ったクラスはヘッダーファイルにUIWebViewDelegateプロトコルを追加しなくてはならない。
//例
@interface WebAppDelegate : NSObject <UIApplicationDelegate,UIWebViewDelegate> {}

[iP]Objective-Cの文法メモ(ActionScript3.0との比較的な):インスタンスの作り方

クラスのインスタンスの生成方法
AS3はこんな感じ


//AS3
//newでコンストラクタを実行。
var hoge:MovieClip= new MovieClip();

obj-cはnewでなくて、各クラスによって色んな初期化メソッドが用意されているみたい。


//Objective-C
//NSStringの場合

//直接文字列を入れて初期化
NSString* str = @"HOGEHOGEO";
//NSString専用の初期化用のメソッドを使う
//文字列から生成
NSString* str = [NSString stringWithString: @"HOGEHOGEO"];
//既存の数値を利用して生成
NSString* str = [NSString stringWithFormat: @"ほげ:%d",100];

※またどのクラスでも通用する汎用の初期化メソッドもある。
(これがASのnewに近いのかな)
[[クラス名 alloc] init]
allocでメモリを確保して、initメソッドを実行
(initメソッドはNSObjectのメソッド)
あとallocでメモリ領域を確保した場合は使用後は自分で破棄しないとダメ
(iPhoneはGC無いので)
破棄は
[インスタンス名 release];


//Objective-C
//allocでインスタンス用のメモリを確保し、initを実行
NSString*  str = [[NSString alloc] init];
//※ただしNSStringのインスタンスは文字列の上書きができないので上記でインスタンスを作ると中身が空っぽのインスタンスができるだけとなる。
NSLog(@"%@",str);//出力:(ブランク)
//破棄
[str release];

2010/05/21:追記
objective-cでもnewを使ったインスタンスの生成はできる


//newを使った例
NSDate* date = [NSDate new];
//newを使わない(上と同じ意味)
NSDate* date = [[NSDate alloc] init];

[iPhone]Objective-Cの勉強メモ:デリゲートについて

アプリケーション自身とか、オブジェクト(クラス)が最初から持っている固有の動作(イベント的なメソッド?)がある。
たとえば、
アプリ起動時に実行されるメソッド、とか
アプリ起動中に着信があった場合に実行されるメソッド、とか
アプリ終了時に実行されるメソッド、など。

これらのメソッドは誰が実行するかを決めた上で、メソッドの中身を実装する必要がある。
誰が(どのクラスが?)、を決める作業をデリゲートを登録するという。
登録はIBのInspectorウィンドウから行う。
(IB使わなくてもObj-Cからも可能)
デリゲートとして登録されたクラスにそれぞれのメソッドを実装することで機能として使えるようになる。

感覚的には各クラスに用意されているメソッドをオーバーライドしているのと同じだろうけど、サブクラスを作る必要がなく、関連の無いクラスからでも、(オーバーライドしたようなメソッドとして)実行することができる。
IBで配置したオブジェクトについていちいちサブクラス作るのメンドイからこの仕組みがあるのかも。

[iPhone]Objective-Cの勉強メモ(ActionScriptとの比較的な):デバッグ出力はNSLog

Objecttive-CにおけるASでいうところのtraceにあたるものは、NSLog()
c言語ベースなのでprintf()でもコンソールに出力できるけどWarningがでたりするのでNSLog使った方がいいみたい。
(Object型のデータの出力に特化って感じかな?)

書き方は、printfとかと同様に変換指定子を使う。%+記号


//%@でオブジェクト型のデータ
NSLog(@"結果は:%@",@"あいうえお");//出力:結果は:あいうえお

[iPhone]C ポインタについて

すぐにこんがらがるのでメモ
ポインタとは、(変数の)メモリ上のアドレスの番地を格納するための仕組み


//ポインタの定義
//型名 *変数名
int *p;
int* p;//*の位置はこの書き方でもよい

int a=100;
//変数aのメモリ上のアドレスは、&aとなる。
//ポインタpにaを参照させるには、
p = &amp;a;//*pではないことに注意
//ポインタからaの値を取得するには
int b=*p;
printf(b);//出力:100

*の使い方についての注意
定義するときの*と、それ以外の*では意味合いが異なるらしい


//整数定義
int a = 100;
//整数型のポイントを定義
int *p;
*p = a;//これはNG
//定義後のポインタ変数に参照させるには、p = &a;
//ただしポインタ定義時の初期化でaを代入するのはOK
int *q = a;//これはOK
//定義するときの*と、それ以外の*では意味合いが違うということらしい

配列のときは配列名には、&はつける必要がない
ポインタ名は配列と同じようだ。


int a[20] = {1,12,23,34,45};
int b = 100;
int *pa;
int *pb;
pa = a;//&aにはならない
pb = &b;

//配列aの2番目の値を取得するには
//配列aを使う場合
printf("%d\n",a[1]);//出力:12
//ポインタpaを使う場合
printf("%d\n",*(pa+1));//出力:12
printf("%d\n",pa[1]);//出力:12

メモリを確保したポインタも配列と同じように扱える


int *bufa;
//100バイト分のメモリを確保
bufa = (int *)malloc(sizeof(int)*100);
bufa[10] = 123;
//配列のように参照
printf("%d\n",bufa[10]);//出力:123
//ポインタとして参照
printf("%d\n",*(bufa+10));//出力:123

[iPhone]Objective-Cの勉強メモ(ActionScriptとの比較的な):アウトレット・アクション

obj-c、1ヶ月くらい触らなかったら知識がほとんどすっとんでる。。。
最初はある程度まとめてどかっとやらないとマズイね。。。

以前とダブルこともあるだろうけどメモしていく。

◆アウトレット
:Viewに置いてあるオブジェクトの名前。
(ASでいうとインスタンス名みたいなもの)
スクリプトファイル(○○.h)でアクションを定義して、InterfaceBuilder(IB)で紐づける。
(スクリプト内で任意のオブジェクトを操作したいときのみアウトレットを定義)

◆アクション
:Viewにおいてあるオブジェクトに起因するイベントハンドラメソッド的なもの。
(AS3でいうとリスナー関数みたいなもの)
これもIBを使ってView上のオブジェクトと紐づける(addEventLisner()的な感じ)

※ASと違うところは、アウトレットは定義しなくても、アクションだけでも使える。
(オブジェクトとアクションの紐付けはIBでできるので)
(ASはインスタンス名をつけないとaddEventListener()使えないよね)
またアクションは引数でオブジェクトを取得可能:(id) sender
(AS3での、e.target的な)
アクションの対象オブジェクトだけをスクリプトで操作(透明にするとか)するなら、アウトレットなしで、アクションだけでOK
でも、アクションの対象外オブジェクトもスクリプトで操作する場合は、アウトレットの定義が必要。