つねぴーblog

元「とある研修医の雑記帳」。アウトプットが趣味です。医学以外の事も投稿するやもしれません。

iphoneアプリ開発まとめ

何も知らない初心者がiphoneアプリを作るまでの簡単な流れです。
最初はメモ的ですが徐々に詳しくしていきます・・・!

int main(int argc, const char * argv[])
{
プログラムの内容
}

作成したプログラムを実行する場合、main関数の部分から処理が始まる。


int main(int argc, const char * argv[])
{
@autoreleasepool{

NSLog(@"Hello,World!");
}
return 0;
}

@autoreleasepool{}とはメモリ管理を行うための記述で{}に囲まれたインスタンスを自動開放プールに登録するという意味。

NSLog(@"");とすると""の間に好きな文章を表示させることが出来る。

return0とはプログラムがここで終わるという目印。

int main(int argc, const char * argv[])
{
@autoreleasepool{

int suuji;
suuji=3;


NSLog(@"数字の大きさは%dです",suuji);
}
return 0;
}

intは変数の型。整数を入れることが出来る。
suujiは変数の名前。好きな名前を入れて良い。
ここではNSLog内のsuujiが%dに代入されている。%dのような記号を変換指定子という。

ちなみに主要な変換指定子は
int型・・・%d
char型・・・%c
float型・・・%f
である。


★関数

☆関数の定義

void 関数名(void){
処理の内容
return;
}

例えば50×50の計算結果を表示する関数multiple50という関数を作るとすると

void multiple50(void){
NSLog(@"50×50の計算結果は%dです",50*50);
return;
}

というように関数を定義することが出来る。

☆関数の呼び出し

関数名();

関数名の後に括弧を付けるだけでよい。

実際にはどのようになるのか、メイン関数を含めて描いてみると・・・

void multiple50(void){
NSLog(@"50×50の計算結果は%dです",50*50);
return;
}

int main(int argc, const char * argv[])
{
@autoreleasepool{

NSLog(@"作った関数を呼び出します。");
multiple50();
NSLog(@"呼び出しました");
}
return 0;
}


ポイントとしては、main関数の外の場所に作った関数を書く。
また、main関数の中からそれを呼び出す場合はmain関数よりも先に定義する。
コンパイラは上から順に呼んでいくので、main関数内で呼び出される前に定義が済んでないとバグってしまうからである。
呼び出されたmutiple50という関数が最後まで処理されるとmain関数に戻り、続きの処理が始まる。



☆引数と戻り値

上で紹介した関数multiple50というのはmultiple50内の内容をただ実行するだけであったが、関数は互いにメッセージを送ってそれを元に処理をすることが可能である。例えばmain関数である数字を指定するとその数字の2倍の数字を求めてくれる関数なんというのも作ることが出来る。そのためには呼び出し元のmain関数から相手の関数へ数字を渡さなければならないが、その値のことを引数と呼ぶ。

関数名をbaiとすると
bai();
のようにして関数を書くことになるが、()の中に好きな数字を入れて2倍に返してもらうようにしてみよう。
main関数の中で
bai(13);
とすればよいのである。

一方関数baiの中はどのような分にすればよいのかというと

void bai (int x)
{
NSLog(@"main関数で渡された数字の2倍は%dです",2*x)
return;
}

関数名baiの後には()の中に受け取るデータの型を書いておきます。今回なら整数と言うことでint型。
また、呼び出し元から相手先の関数に渡す因数のことを実引数、相手先関数が呼び出し元から受け取る値のことを仮引数という。先の例では呼び出し元から渡した13という数字が実引数でxというのが仮引数である。このxという変数名は別に何でも良い。yでもzでもhensuとかでも。


void bai (int x)
{
NSLog(@"main関数で渡された数字の2倍は%dです",2*x)
return;
}
int main(int argc, const char * argv[])
{
@autoreleasepool{

NSLog(@"作った関数baiに数字18を入れてみます。");
bai(18);
}
return 0;
}


☆複数の引数

引数は好きなだけ渡すことが出来る。
例えば関数tripleがあるとして
triple(3,8,5);
のように好きな数字3つを入力して

int triple(int x, int y, int z)
{

a=x+y+z;
return a;
}

のようにすることが可能。つまりtriple関数内でaという変数をつくり、引数のx,y,zを足しあわせてaに代入する。
そしてreturnでaを返しているのである。関数名tripleの左側にあるintというのは戻り値の型である。

そしてreturnされたaをメイン関数でどう取得すればいいのかということであるが、

メイン関数内で
int a = triple(3,8,5);

のように記述するのである。



また、returnの次に文字ではなくて式を書くことも可能なので

int triple(int x, int y, int z)
{
return x+y+z;
}

のように書き換えることも可能。


☆void型とは

void hikizan(intx,y)
{
NSLog(@"受け取った二つの変数を引くと%dになります。",x,y);
return;
}

というようなvoid型の関数hikizanを定義することが出来ます。void型というのは値を持たない戻り値ということです。
つまり、メイン関数に何か変数を返す必要が無く、void hikizanという関数の中で二つの変数の差を表示することが完了しています。こういう場合は戻り値の型にintではなくvoidを使いましょう。

関数についてまとめておくと

戻り値の型名 関数名(引数の型 変数名)//引数がない場合は引数の型と変数名はvoidとする。
{
プログラム内容
return 戻り値;//戻り値の型名がvoidの場合、この戻り値は必要ない。
}


★構造体


構造体とは複数の変数を一つにまとめた型のことである。
例えば人間というデータなら、身長、体重、年齢などなど様々なデータを持っている。
身長や体重は小数点で表されるために型はfloat
年齢は整数で表されるために型はint
といった具合にわけることができる。

人間というデータに関して個々の値に対する型名と変数名は上の通りであるが、「人間」というデータに対する型を決めるのが構造体の役割なのである。構造体も型名を持ち、必ず型名はstructという文字列から始まる。
例えば人間というデータの構造体を書くならば

struct person{
int nenrei;
int nensyu;
float shincyo;
float taijyu;
};
といった具合です。

しかし、struct personという構造体変数名は長い。そこでtypedef文を利用することで短くすることが可能。
例えばpersという短い変数にしたい場合は

typedef struct person pers;

とかく。つまりpersは別名でありあだ名のようなものである。

struct person{
int nenrei;
int nensyu;
float shincyo;
float taijyu;
};
typedef struct person pers;

このように最後にtypedef文を追加するのである。



もっとシンプルな書き方をするならば

typedef struct Person{
int nenrei;
int nensyu;
float shincyo;
float taijyu;
}pers;

のようにすることも出来る。これで晴れてpersという簡単な型が作成できたことになる。



☆構造体のメンバーに値を収納する。

intやfloatといった型には一つの値しか持つことが出来ないが、上で作った構造体persでは4つの値を持つことが出来る。

まず、persという型にも変数を宣言する必要がある。
例えば

pers a;

としてaという変数を宣言する。続いて、aという変数には4つの型があるので、値を収納する際にはaのどこに収納するのかを決めなければならない。それを指定するのがドット演算子.といわれるものである。

例えば、

a.taijyu

とすれば変数aの体重のデータにアクセスすることが出来る。
更に

a.taijyu=65.0;
とすれば体重に65.0という値を入れることが出来るのである。

この場合、aを構造体全体を表す構造体変数
taijyuを構造体の中の個々のデータを表すメンバー変数という。


メンバー変数へのアクセスを公式として表すならば

構造体変数名.メンバー変数名と表す。

☆構造体を引数として渡す

#import

typedef struct Person{
float height;
float weight;
int birthYear;
int birthMonth;
int birthDay;
}Person;

void hyoujiPersondate(Person b)
{
NSLog(@"引数の身長データは%fです",b.height);
NSLog(@"引数の体重データは%fです",b.weight);
NSLog(@"引数の生年月日は%d年%d月%d日です",b.birthYear,b.birthMonth,b.birthDay);
return;
}

int main(int argc, const char * argv[])
{

@autoreleasepool{

Person a={182.3,65.0,1986,5,23};

hyoujiPersondate(a);

}
return 0;
}

person型の定義は事前にしておくのがポイント。


☆列挙体

列挙するための構文。春夏秋冬とか月火水木金土日というように。





★クラス

例えば三角形をクラスと考えると

三角形という概念に含まれるたくさんの三角形全てがインスタンス。
直角三角形も二等辺三角形も正三角形も三角形というクラスのインスタンス。

インスタンスのことをオブジェクトとも言う。また、クラスを持たないインスタンスや空のインスタンスもオブジェクトという。


インスタンス変数・・・例えば三角形のインスタンスならば底辺や高さなどをインスタンス変数と考えることが出来る。


クラス宣言の仕方

@interface クラス名:スーパークラス名
{
@public
インスタンス変数の定義;
}
@end

三角形のクラスだとすると

@interface sankaku:NSObject
{
@public
int teihen;
int takasa;
}
@end

これで三角形のクラスが出来たことになる。ただしこれはただの概念に過ぎず、実物(インスタンス)は作られていない。

クラス名 インスタンス名=[[クラス名 alloc] init];

Sankaku *sankaku_A=[[Sankaku alloc] init];

こう書くことによって三角形のインスタンスは生成されたことになる。
しかしながら、肝心の底辺の長さと高さが決まっていない。

例えば高さ20、底辺5とするならば

sankaku_A->=takasa=20;
sankaku_A->=teihen=5;

のようにする。->をアロー演算子という。
これを見てもらうと構造体とすごく似ていることがわかる。
【インスタンスとインスタンス変数】の関係は【構造体変数とメンバ変数】の関係と近い。
構造体の時はアロー演算子でなくドット演算子を使うことを思い出して欲しい。

尚、クラスにはメソッドやカプセル化という構造体にはない概念が存在するのでそこが重要である。





少し飛んで
■クラスの継承

例えば図形クラスの下に三角形クラスや四角形クラスを考えることが出来る。
共通点としては色がある、面積がある。異なってる点としては辺の数、内角の和。

@interface クラス名:スーパークラス名
{
@public
インスタンス変数の定義;
}
@end

全ての大元となるクラスをNSObjectという。


まず、図形クラスの定義

typedef enum Color{RED,GREEN,BLUE}Color;
と色を指定するための列挙体を定義してーの

@interface Zukei: NSObject
{
@protected
Color cl;
}
@property Color cl;
@end

//@protectedにしているのでzukeidクラスをスーパークラスとして持つサブクラスからも参照できるようになる。
//次にメソッドの定義

@implementation
@synthesize cl;
@end

//@senthesize宣言により、セッターとなるsetCLメソッド、ゲッターとなるclメソッドを同時に定義している。


続いて今のzukeiクラスをスーパークラスとして持つ新しいsankakuクラスを定義する。
sankakuクラスが持つインスタンス変数とshちえは色、底辺、高さとする。色に関してはスーパークラスであるzukeiクラスも持っているためにその部分だけは新しく定義する必要がない!

@interface Sanakaku:Zukei
{
@private
int teihen;
int takasa;
}
@property int teihen, takasa;
@end

@implementation Sankaku
@synthesize teihen, takasa;
@end


ここまでのをもとにサンプルコードを書いてみる
////////////////////////////////////////////////////////////////////////


#import

typedef enum Color{RED, GREEN, BLUE}Color;

@interface Zukei: NSObject
{
@protected
Color cl;
}
@property Color cl;
@end

@implementation Zukei
@synthsize cl;
@end

@interface Sankaku: Zukei
{
@pricate
int teihen;
int takasa;
}
@property int teihen,takasa;
@end

@implementation Sankaku
@synthesize teihen,takasa;
@end

int main(int argc, const char * argv[])
{

@autoreleasepool{

Sankaku *sankaku_A=[[Sankaku alloc] init];

sankaku_A.cl= GREEN;

sankaku_A.teihen=6;/////これは[sanakaku_A setTeihen:6]を簡略化してsankaku_A.teihen=6;のように書いている。(@propertyと@synthesizeをしたおかげ。)

sankaku_A.takasa=4;

NSLog(@"三角形Aの底辺の長さは%d、高さは%dです",sankaku_A.teihen,sankaku_A.takasa);
NSLog(@"三角形Aのカラーは%dです(0:RED,1:GREEN,2:BLUE)",sankaku_A.cl);

}

return 0;

}


■オーバーライド

オーバーライドはスーパークラスで定義されたメソッドを子供クラスで再定義することである。(上書き保存)



★selfの使い方【大事】

ダメな例

  • (void) call_iMethod

{
ClassB1 *instance_B1 =[[ClassB1 alloc] init];
[instance_B1 iMethod];
return;
}

こういうふうにselfを使わずに別のインスタンスを生成してインスタンスメソッドを実行してしまうとそれは自分自身のインスタンスではなく、インスタンス変数の異なる、新しい全く別のインスタンスによる処理となってしまう。

よって次のようにかく

正しい例

  • (void)call_iMethod

{
[self iMethod];
return;
}



/////////////////////////////コード例//////////////////////////////////


#import

@interface ClassB1:NSObject
@end

@implementation ClassB1
+(void)cMethod

{
NSLog(@"cMethodを実行しました");
return;
}

  1. (void)call_cMethod

{
NSLog(@"cMethodを呼び出します);
[self cMethod];
return;
}

  • (void)iMethod

{
NSLog(@"iMethodを実行しました");
return;
}

  • (void)call_iMethod

{

NSLog(@"iMethodを呼び出します);
[self iMethod];
return;

}
@end

int main (int argc, const char * argv[])
{

@autoreleasepool{

[ClassB1 call_cMethod];
[[ClassB1 alloc] call_iMethod];

}
return 0;
}