2012-02-12 7 views
0

これは賛否両論のための簡単なものでなければなりません(免責事項、私はObj-Cのようなものですが、主にC#で使用しています)。私はUIViewControllerサブクラスを持っています。そのプロパティの1つがAVAudioPlayerオブジェクトです。このコードを書くとき:なぜオブジェクトを割り当てて、インスタンス変数をObj-Cで設定する必要がありますか?

NSString *path = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"caf"]; 
NSURL *url = [[NSURL alloc] initFileURLWithPath:path]; 
[player initWithContentsOfURL:url error:NULL]; 
[url release]; 
[player setDelegate:self]; 
[player prepareToPlay]; 
[player play]; 

何も起こりません。

NSString *path = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"caf"]; 
NSURL *url = [[NSURL alloc] initFileURLWithPath:path]; 
AVAudioPlayer *ap = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL]; 
self.player = ap; 
[ap release]; 
[url release]; 
[player setDelegate:self]; 
[player prepareToPlay]; 
[player play]; 

...すべてが美しく動作します:明確にそれを行うための正しい方法である

私はこれを行います、。

なぜオブジェクトを割り当ててからプロパティを設定する必要がありますか?これはあまりにも一般的な質問である場合はお詫び申し上げます。

+0

可能であれば、ARCを使用すると、保持/解放または自動解放のステートメントはありません。コンパイラが行うことができるいくつかの最適化もあります。また、便利なメソッドがあります: 'NSURL * url = [NSURL URLWithString:path];'これはあなたの人生を楽にすることができます。 – zaph

答えて

5

これは、最初の例では、allocでAVAudioPlayerを作成していないためです。これは、実際にはメモリに有効なAVAudioPlayerを持っていないことを意味します。

また、init *の戻り値を使用していません。 initはインスタンス自体で動作することが多いので、これは多くの場合、allocを実行してそれをプレーヤに割り当てた場合にはうまくいくでしょうが、これに頼ることはできません。返り値をClass *var = [[Class alloc] init]形式。

あなたは短時間勤務のコードを望んでいた場合、あなたはクラスからオブジェクトを作成する必要が

self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL]; 
4

最初に、あなたのplayerインスタンス変数を使用すると、C#でオブジェクトを作成する際に参照フィールドを自動的にnullに設定されている多くのように、nil(C#でnullに相当)に設定されています。しかし、C#とは異なり、nilに何かを呼び出すと、何もしません(NullReferenceExceptionを投げることに反対)。したがって、何かをする前に何かをplayerに割り当てる必要があります。それ以外の場合、呼び出しは自動的に失敗します。

C#では、new Foo()があります。これは実際には2つのことを行います。Fooオブジェクトにメモリを割り当て、割り当てられたメモリのコンストラクタを呼び出します。一歩一歩Objective-Cでは、これらの2つのステップが異なります。 allocはメモリを割り当て、initは "コンストラクタ"です。最初のコードスニペットでは、割り当て手順をスキップして何も起こりません。あなたはこれを使って、正しい結果を得る必要があります。

player = [AVAudioPlayer alloc]; 
player = [player initWithContentsOfURL:url error:NULL]; 

それとも、もっと簡潔に:

player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL]; 

init方法は、実際に値を返すことに注意してください。それはあなたが後で

id foo = [Foo alloc]; 
foo = [foo init]; // correct 

id foo = [[Foo alloc] init]; // correct too 

id foo = [Foo alloc]; 
[foo init]; // incorrect 

理由はinit方法が完全に別のオブジェクトを返すことが許されていることであるオブジェクトを参照するためにそれを使用することが重要です。それは異なるクラスのものであってもよい。 Objective-Cは、あなたが返すタイプが広告するクラスと同じメソッドを実装している限り、「ダックタイプの」言語であり、すべてが良好です。たとえば、Mac OSでは、実際にはNSStringというインスタンスは表示されず、NSCFStringなどのように表示されます。

Objectiveの自動保持カウント機能をオンにすることをおすすめしますほとんどのメモリ管理ルーチン(retain/release)を解放します。

+0

+1のC#の詳細 –

1

[player initWithContentsOfURL:url error:NULL]; 

を置き換えることができます。

この男はあなたのC#コンストラクタと同じです。新しいオブジェクトのメモリを割り当て、パラメータurlおよびNULLを使用して初期化します。

[[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL] 

あなただけが、あなたはインスタンス変数として「self.player」を必要としないで作業しているオブジェクトの生活の中で一度プレーヤーを使用している場合。完全にあなたのヘッダファイルからそれを削除し、このように見えるようにコードを変更します。

NSString *path = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"caf"]; 
NSURL *url = [[NSURL alloc] initFileURLWithPath:path]; 
AVAudioPlayer *ap = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL];  
[url release]; 
[ap setDelegate:self]; 
[ap prepareToPlay]; 
[ap play]; 
[ap release]; 

あなたの周りにそのプレイヤーを維持するか、別の場所にアクセスする必要がある場合、あなたはあなたのインスタンス変数「プレイヤー」を維持する必要があります。あなたのコードは次のようになります。

NSString *path = [[NSBundle mainBundle] pathForResource:@"example" ofType:@"caf"]; 
NSURL *url = [[NSURL alloc] initFileURLWithPath:path]; 
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL]; 
[url release]; 
[player setDelegate:self]; 
[player prepareToPlay]; 
[player play]; 

その後、あなたは自己クラスのdeallocをのような後の時点でプレイヤーを解放する必要があります。

関連する問題