为什么我必须分配一个对象并在Obj-C中设置我的实例变量=该对象?
好的,这对于那里的专业人员来说应该是一件容易的事情(免责声明,我是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];
...一切精美的作品。
为什么我需要分配一个对象然后设置我的属性等于那个?道歉,如果这是一个太常见的问题。
这是因为在你的第一个例子中,你没有用alloc创建AVAudioPlayer。这意味着你实际上在内存中没有有效的AVAudioPlayer。
而且你还没有使用init *的返回值。由于init经常在实例本身上工作,如果你已经完成了alloc并将其分配给了播放器,这可能会在很多情况下起作用,但是你不能依赖这个,并且它的约定使用返回值与Class *var = [[Class alloc] init]
表单。
如果你想更短的工作代码,你可以用
self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL];
最初,您的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
)。
对于C#的详细信息 – 2012-02-12 23:44:27
更换
[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。
如果可能使用ARC,则不存在保留/释放或自动释放语句。还有一些编译器可以进行的优化。还有一些便利的方法,比如:'NSURL * url = [NSURL URLWithString:path];'这可以让你的生活更轻松。 – zaph 2012-02-13 00:03:41