2011年11月17日木曜日

【メモ】iPhoneアプリケーションの読み込み順序


●最初にmain.mのUIApplicationクラスをインスタンス化
●info.plistを読み込み、main xib file base nameからxibファイルを探す
●xibファイルを読み込み、記述に従いインスタンス化(今まではMainWindow.xibを読み込み、そこからViewControllerのxibファイルをロードしていたが、XCode4.2からAppDelegate.mに該当のソースが追加され、MainWindow.xibがなくなってしまったようです。これに2-3日はまりました)

2011年11月10日木曜日

XCodeでビルド後、iPhoneで実行する前にDon't know how to run. Try "help target" というエラーが出る件

Don't know how to run. Try "help target" というエラーが出てはまったので直った方法をシェア。
●試したこと
クリーニング
XCodeの再起動
プロパティの見直し
コンパイラの変更
→どれもうまくいかず。。
●直った方法
実機のポータルへの登録しなおし


アクセサ

インスタンスの値や属性を見たり変更したりするためのメソッドを作って使うのが流儀。
該当インスタンスの値を直接みたり変更するのではなくメソッドを作って変更する。

値や属性などを確認するのがゲッタ(getter)
値や属性を変更するのがセッタ(setter)
という名前としてつけられてる。
例)
num1 num2 num3というインスタンス変数があった場合の
num1だけ見たり変更したりするゲッタセッタ
-(int)num1{return num1;) //ゲッタ(ただnum1の値を返す)
-(void)setNum1 : (int)newvalue{
num1 = newvalue; //セッタ(num1の値をnewvalueに変更)
}

アクセサは@property @symthesizeを書くことで同様のことができる。
@propertyの書き方
例)
@property (retain,nonatomic) (id) *count;
のように属性などをつけて定義する。
アクセサを作る対象がオブジェクトの場合、retain nonatomicはつけるのが慣例
nonatomic とretainについて後で確認。
この例のretainは使用中はメモリから消されないようにする

あるインスタンスから他のインスタンス変数にアクセスする方法

例)obj1のval1に他のインスタンスからアクセスするには
obj1->val1
という書き方をする。
同じクラス内のインスタンスのみ利用可能。
使う場合にもクラス名でキャストしておく必要がある。

-(id)makerandnum:(mknum *)num
{
num1 = num->num2;
//mknumクラスの型にキャストされたインスタンス変数numにアクセス
}
☆インスタンス変数の使える範囲の指定
num->num1のように他のインスタンス変数を利用できるが、インスタンス変数へのアクセスできる
範囲を制限することができる。どこからでも変更、読み込みができたり、クラス内でしか読めないようにできたり。

@private
宣言したクラス内だけ利用可能
サブクラスからも使えない。
@protected
宣言したクラスとサブクラスから利用可能
何も指定しないと@protectedが適用される
@public
どこからでも利用可能
書き方
@interface num1 : num
{
id inclementvall;
@public
int decval;
@private
double outval;
int testval1;
@protected
int testval;
}
@end
というように種類ごとに定義する。

インターフェースに他のクラスを使うとき

インターフェースを定義するときに、他のクラスを型としてインスタンス変数に定義することができる。
その方法として、インターフェースを定義するヘッダファイルの最初に@class つかうクラス名
を宣言し、実処理を行うときに該当クラスのヘッダファイルをインポートする。
例)
@class class1
@interface newclass :NSObject
class1 *theclass1;
@end

//ヘッダファイル部
import "class1.h"
→使う暮らすヘッダファイルをインポートする。

型とクラス

インスタンス化するとき、id型を利用するが、特定のクラスのインスタンスということを明記することができる
クラス"class"専用のインスタンスを言うことを書きたい場合
class *x
というように*をつける。
このように生成されたオブジェクトはポインタとして生成され
class *x,*y
x = [[class alloc] val : 0];
x = y;
とした場合。xで実行した結果がそのままyに引き継がれる。

継承して新しく作ったクラスは、スーパークラス用に定義されたクラス名に入れることができる
例) class1 *a
@interface class : NSObject
- (void)hello
@end
@implemantation
なんちゃら
@end
@interface class2 : class
-(void) hello
@end

int main(void){
class *a,*b;
a = [[class alloc] init];
b = [[class2 alloc] init];
}
というようにclass1用に作ったものでも継承して作られたclass2に入れることができる。
ただし、スーパークラスで定義されたメソッドのみしか使えない。
使いたい場合は、class2の型にキャストして利用する。

class1 *a,*b;
a = [[class1 alloc] init];
b = [[class2 alloc] init];
[a class1onlymethod];
[b class1onlymethod];//class2でclass1から継承したclass1にあるメソッドを利用してもエラーでない

[b class2onlymethod];//オーバーライドしたものはエラーが出る
[(class2 *)b class2onlymethod];//class2用の型にキャスト

テクニック
if文の条件の評価順序をうまく使い、インクリメントや文字列の評価をする
例)if (p && *p)
pが空の場合はそれ以降の評価は行われない。
ポインタのpかどうか調べる際、pが空だとコンパイラが落ちるので落とさずに値の評価ができる

継承とクラス

[self]でクラス自身のメソッドを呼び出したとき、上書きされていない継承したメソッドを呼んだとき
スーパークラスのメソッドが呼ばれる。
スーパークラスのメソッド内で[self]でメソッドが呼ばれたとき、スーパークラス内のメソッドが参照されるのではなく、自分のクラスのメソッドが呼ばれる(オーバーライドされたものが呼ばれる)


実装手順
ヘッダーファイルにインターフェースを書く
mファイルに実処理を@implementation以下にインターフェースに対応した処理を書いていく

実行プログラム上で書いた処理の呼び出しを行う
@interface
-変数やクラス名定義
@implementation
-色々処理
int main(void)
{
id x = [[newinstance alloc] init];//インスタンス生成
[x method1];//インスタンスのメソッド呼び出し
}
外部からのメッセージで動くメソッドの場合はinterface部分にメソッド名を定義する必要があるが
そのクラス内部でしか使わない内部用のメソッドの場合はインターフェースは書かなくてもよい。
[self]で呼び出してつかったりする。
例)カウンターアプリでダウンアップそれぞれメソッドを作るが、アップダウンと同時に音を鳴らせる場合、内部で音を鳴らせるメソッドを作成し、[self]で呼び出すなど
この場合、最初の部分に定義する必要がある([self]で呼び出される前に定義)

継承について

クラスの機能を受け継いで新しい機能をつけたしたクラスを簡単につくることができます。
クラスの機能を受け継ぐことを継承といいます。

クラスA→クラスB(Aの機能にメソッドを一個追加)→クラスD(A+Bの機能)
→クラスC(Aの機能に変数とメソッドを追加)

クラスAのインスタンス変数名やメソッド名はBでもCでもそのままつかえます。
さらにクラスBからクラスDのように機能をどんどん継承して自由に機能を利用することができます。

継承する元のクラスをスーパークラスと言い、継承して新しく作ったクラスはサブクラスといいます。

iPhone開発の場合、全ての大本のクラスはNSObjectsというクラスなので
特段継承するクラスを作っていない場合などはNSObjectsを継承させる。

クラスを継承する場合のクラスの書き方
@interface newclass : NSObjects または継承するクラス名(スーパークラス)
{
インスタンス変数;
}
-メソッド
@end;

継承とメソッドのオーバーライドについて
クラスA
クラスB
クラスC
の3つのクラスがあったとして、A→B→Cという感じで継承していた時
クラスAにはa b cの3つのメソッドが定義されているとする。
クラスBでbメソッドの定義を書き換えたら、クラスCで継承されたとき書き換えられたbメソッドをつかう。
他に書き換えられてない場合、大本のAのメソッドが継承され、使われる。
☆クラスBで書き換えたbメソッドではなく、スーパークラス(クラスA)の書き換え前のbメソッドを使いたい場合、superというものに対してメソッドを引数にして呼び出すとスーパークラスのメソッドが呼ばれる。
例)
[b]→自分で書き換えたメソッドが呼ばれる
[super b]→スーパークラスのbが呼ばれる

☆イニシャライザについて
インスタンス変数の初期化、サブクラスで初期化を行う場合
-(id)init
{
self = [super init];
if(self =! nil){
year = @"";
//初期化するコードが入る
}
return self;
}

Objective-cの書き方基本

オブジェクトはid型という型で定義される
例 id temp;
あるオブジェクト(obj)にメッセージを送るとき
[obj messege];
とかく。messageを処理した値が帰ってくる。
返り値がオブジェクトの場合、さらに[[obj message] messsage2]のように
さらにメッセージを送って処理させることもできる

クラス→インスタンス生成方法
クラスにメッセージを送る
とりあえずインスタンス作る場合
[classname alloc];
というようにallocというメッセージを送って空のインスタンスを作る
この後、初期化処理を行う。初期化処理するためのメソッドはイニシャライザといいinitもしくはinitなんちゃらという名前になるルール
☆インスタンスを作って初期化する例
[[class alloc] init];

2011年11月2日水曜日

テスト

#import "sm2ViewController.h"

@implementation sm2ViewController

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Release any cached data, images, etc that aren't in use.
}

#pragma mark - View lifecycle
//数値を表示
-(void)updatedisplay
{
    display.text=[NSString stringWithFormat:@"%d",count];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    srand(time(NULL));
    [NSTimer scheduledTimerWithTimeInterval:1.5 
                                     target:self 
                                   selector:@selector(move:) 
                                   userInfo:nil 
                                    repeats:YES];
    //解像度取得
    CGRect r = [[UIScreen mainScreen] bounds];
    CGFloat w = r.size.width;
    CGFloat h = r.size.height;
    NSLog(@"%f",h);
    
    //音の指定
    NSString *path= [[NSBundle mainBundle]
                     pathForResource:@"Alarm" ofType:@"caf"];
    NSURL *url=[NSURL fileURLWithPath:path];
    //NSLog(@"%s",path);
    //
    AudioServicesCreateSystemSoundID((__bridge CFURLRef)url,&SoundID);

}
-(void)move:(NSTimer *)timer
{
    //アニメーションの動きの定義
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1.5];
    
    //iPhoneの解像度を取得する(これをすることで未来の解像度にも対応できるかも)
    CGRect r = [[UIScreen mainScreen] bounds];
    CGFloat w = r.size.width;
    CGFloat h = r.size.height;
    
    //CGFloatはfloat型なのでintにキャスト
    int wid=(int)w;
    int hei=(int)h;
    
    //x,y座標rand()%hogeで0〜(hoge-1)までの数値をランダムで出力
    int x = rand()%wid;
    int y = rand()%hei;
    
    //targetアウトレットのcenterプロパティ
    target.center = CGPointMake(x,y);
    
    //アニメーション終了
    [UIView commitAnimations];
    
}
//あたらなかった場合のペナルティ
-(IBAction)nohit;
{
    count=count-1;
    [self updatedisplay];
}

//あたった場合に音が鳴る
-(IBAction)smash
{
    AudioServicesPlaySystemSound(SoundID);
    AudioServicesPlayAlertSound(SoundID);
    AudioServicesPlayAlertSound(kSystemSoundID_Vibrate);
}

//あたった場合カウントアップする
-(IBAction)countsmash
{
    count = count+1;
    [self updatedisplay];
}
//解像度取得メソッド
-(void)getresolution
{
    CGRect r = [[UIScreen mainScreen] bounds];
    CGFloat w = r.size.width;
//    CGFloat h = r.size.height;
    NSLog(@"%f",w);
}

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    // e.g. self.myOutlet = nil;
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
}

- (void)viewWillDisappear:(BOOL)animated
{
 [super viewWillDisappear:animated];
}

- (void)viewDidDisappear:(BOOL)animated
{
 [super viewDidDisappear:animated];
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    // Return YES for supported orientations
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown);
    } else {
        return YES;
    }
}

@end