为什么我必须分配一个对象并将我的实例变量设置为 Obj-C 中的该对象?
好吧,这对于专业人士来说应该是一件简单的事情(免责声明,我在 Obj-C 方面有点菜鸟,主要是在 C# 中使用)。我有一个 UIViewController 子类;它的属性之一是 AVAudioPlayer 对象。当我编写这段代码时:
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];
……一切都很顺利。
为什么我需要分配一个对象,然后将我的属性设置为等于该对象?如果这是一个太常见的问题,我深表歉意。
Okay, this should be an easy one for the pros out there (disclaimer, I'm sort of a noob in Obj-C, mainly I use in C#). I have a UIViewController subclass; one of its properties is an AVAudioPlayer object. When I write this code:
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];
Nothing happens.
When I do this, which is clearly the correct way of doing it:
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];
...everything works beautifully.
Why do I need to allocate an object and then set my property equal to that? Apologies if this is a way-too-common question.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这是因为在第一个示例中,您没有使用 alloc 创建 AVAudioPlayer。这意味着内存中实际上没有有效的 AVAudioPlayer 。
而且您也没有使用 init* 的返回值。由于 init 通常作用于实例本身,因此如果您已完成分配并将其分配给玩家,则在许多情况下这可能会起作用,但您不能依赖于此,并且它的约定是使用带有
Class *var = [[Class alloc] init]
形式。如果您想要更短的工作代码,您可以替换
为
This is because in your first example you are not creating the AVAudioPlayer with alloc. This means you don't actually have a valid AVAudioPlayer in memory.
And also you are not using taking the return value of init*. Since init often works on the instance itself, this would probably work in many cases if you had done the alloc and assigned it to player, but you can't rely on this, and its the convention to use the return value with a
Class *var = [[Class alloc] init]
form.If you wanted shorter working code, you could replace
with
最初,您的
player
实例变量设置为nil
(相当于 C# 中的null
),就像引用字段自动设置为>null
当您在 C# 中构造对象时。然而,与 C# 不同的是,在nil
上调用某些内容不会执行任何操作(与抛出NullReferenceException
相反)。因此,你需要给player
分配一些东西,然后它才能做一些事情;否则,调用会默默失败。在 C# 中,有
new Foo()
,它实际上做了两件事:为Foo
对象分配内存,然后在分配的内存上调用构造函数;一步到位。在 Objective-C 中,这两个步骤是不同的。alloc
分配内存,init
是“构造函数”。在第一个代码片段中,您跳过分配步骤,因此什么也没有发生。您应该使用以下方法获得正确的结果:或者,更简洁地说:
另请注意
init
方法实际上返回一个值。之后使用它来引用该对象很重要。原因是
init
方法允许返回一个完全不同的对象;它甚至可以属于不同的类别。 Objective-C 是一种“鸭子类型”语言,只要您返回的类型实现与您所宣传的类相同的方法,一切都很好。 (例如,在 Mac OS 上,您永远不会看到NSString
的实际实例。相反,您会看到NSCFString
和其他一些实例。)我还推荐您打开 Objective-C 语言的自动保留计数功能,因为它可以让您摆脱大多数内存管理例程(主要是
retain
/release
)。Initially, your
player
instance variable is set tonil
(the equivalent ofnull
in C#), much like reference fields are automatically set tonull
when you construct an object in C#. Unlike C#, however, calling something onnil
does nothing (in opposition to throwing aNullReferenceException
). Therefore, you need to assign something toplayer
before it can do something; otherwise, the call silently fails.In C#, you have
new Foo()
, which actually does two things: it allocates memory for aFoo
object, and then calls a constructor on that allocated memory; all in one step. In Objective-C, those two steps are distinct.alloc
allocates memory, andinit
is the "constructor". In your first code snippet, you skip the allocation step, so nothing happens. You should get correct results by using this:Or, more concisely:
Also notice that the
init
methods actually return a value. It's important that you use it to refer to the object afterwardsThe reason is that the
init
method is allowed to return a completely different object; it can even be of a different class. Objective-C being a "duck-typed" language, as long as the type you return implements the same methods the class you advertise has, everything is good. (For instance, on Mac OS, you'll never see an actual instance ofNSString
. Instead, you'll seeNSCFString
and a couple others.)I also recommend you turn on the automatic retain count feature of the Objective-C language, as it frees you of most memory management routines (
retain
/release
mostly).您必须从类创建对象。
这家伙和你的 C# 构造函数是一样的。它为新对象分配内存并使用参数 url 和 NULL 对其进行初始化。
如果您在正在使用的对象的生命周期中只使用一次播放器,那么您不需要“self.player”作为实例变量。将其从头文件中完全删除并将代码更改为如下所示:
如果您需要保留该播放器或在其他地方访问它,那么您需要保留实例变量“player”。您的代码应该如下所示:
然后您必须在稍后的时间点释放玩家,就像 self 类的 dealloc 一样。
You have to create the object from the class.
This guy is the same as your C# constructor. It allocates the memory for the new object and initializes it with the parameters url and NULL.
If you're only using the player once in the life of the object that you're working in then you don't need "self.player" as an instance variable. Remove it from your header file completely and change your code to look like this:
If you need to keep that player around or access it elsewhere then you need to keep your instance variable "player". Your code should look like this:
Then you'll have to release player at a later point in time like the dealloc of the self class.