为什么我必须分配一个对象并将我的实例变量设置为 Obj-C 中的该对象?

发布于 2025-01-05 09:59:49 字数 894 浏览 0 评论 0原文

好吧,这对于专业人士来说应该是一件简单的事情(免责声明,我在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

七秒鱼° 2025-01-12 09:59:49

这是因为在第一个示例中,您没有使用 alloc 创建 AVAudioPlayer。这意味着内存中实际上没有有效的 AVAudioPlayer 。

而且您也没有使用 init* 的返回值。由于 init 通常作用于实例本身,因此如果您已完成分配并将其分配给玩家,则在许多情况下这可能会起作用,但您不能依赖于此,并且它的约定是使用带有 Class *var = [[Class alloc] init] 形式。

如果您想要更短的工作代码,您可以替换

[player initWithContentsOfURL:url error:NULL];

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

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

[player initWithContentsOfURL:url error:NULL];

with

self.player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:NULL];
幻梦 2025-01-12 09:59:49

最初,您的 player 实例变量设置为 nil(相当于 C# 中的 null),就像引用字段自动设置为 >null 当您在 C# 中构造对象时。然而,与 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 和其他一些实例。)

我还推荐您打开 Objective-C 语言的自动保留计数功能,因为它可以让您摆脱大多数内存管理例程(主要是 retain/release)。

Initially, your player instance variable is set to nil (the equivalent of null in C#), much like reference fields are automatically set to null when you construct an object in C#. Unlike C#, however, calling something on nil does nothing (in opposition to throwing a NullReferenceException). Therefore, you need to assign something to player 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 a Foo 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, and init is the "constructor". In your first code snippet, you skip the allocation step, so nothing happens. You should get correct results by using this:

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

Or, more concisely:

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

Also notice that the init methods actually return a value. It's important that you use it to refer to the object afterwards

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

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

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

The 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 of NSString. Instead, you'll see NSCFString 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).

你好,陌生人 2025-01-12 09:59:49

您必须从类创建对象。

这家伙和你的 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];

如果您需要保留该播放器或在其他地方访问它,那么您需要保留实例变量“player”。您的代码应该如下所示:

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];

然后您必须在稍后的时间点释放玩家,就像 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.

[[AVAudioPlayer alloc] initWithContentsOfURL:url error: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:

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];

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:

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];

Then you'll have to release player at a later point in time like the dealloc of the self class.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文