2012-02-12 63 views
0

好的,這對於那裏的專業人員來說應該是一件容易的事情(免責聲明,我是Obj-C中的noob,主要用於C#)。我有一個UIViewController子類;它的一個屬性是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 2012-02-13 00:03:41

回答

5

這是因爲在你的第一個例子中,你沒有用alloc創建AVAudioPlayer。這意味着你實際上在內存中沒有有效的AVAudioPlayer。

而且你還沒有使用init *的返回值。由於init經常在實例本身上工作,如果你已經完成了alloc並將其分配給了播放器,這可能會在很多情況下起作用,但是你不能依賴這個,並且它的約定使用返回值與Class *var = [[Class alloc] init]表單。

如果你想更短的工作代碼,你可以用

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

最初,您的player實例變量被設置爲nil(的null C#中的等價物),就像當構造在C#的對象引用字段被自動設置爲null。但是,與C#不同的是,調用nil上的某些內容不會產生任何效果(與投擲NullReferenceException相反)。因此,你需要在player之前分配一些東西,然後才能做點什麼;否則,通話會靜默失敗。在C#中,您有new Foo(),它實際上做了兩件事:它爲Foo對象分配內存,然後在該分配的內存上調用構造函數;一步到位。在Objective-C中,這兩個步驟是不同的。 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和其他幾個實例。)

我還建議您打開目標的自動保留計數功能-C語言,因爲它可以讓您免去大部分內存管理例程(主要是retain/release)。

+0

對於C#的詳細信息 – 2012-02-12 23:44:27

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。

相關問題