何时使用 self 访问属性,何时不访问?

发布于 2024-10-15 08:12:22 字数 495 浏览 9 评论 0原文

如果 someObject 是使用 @property (nonatomic, keep) SomeType someObject; 创建的类属性,任何人都可以解释设置 someObject = someOtherObject;self.someObject = someOtherObject; 之间的区别吗?

为了澄清我有这样的事情:

@interface SomeClass : NSObject {
   SomeType* someObject;
}

@property (nonatomic, retain) SomeType* someObject;

@end

我注意到有时当我在没有 self 的情况下使用该属性时,我会得到 EXC_BAD ACCESS,而且它看起来很随机。当我使用 self 时,我的程序将按其应有的方式运行。当我跳过 self 时,我没有收到任何编译器错误或警告,所以我猜它是某种有效的语法?

Can anyone explain the difference between setting someObject = someOtherObject; and self.someObject = someOtherObject; if someObject is a class property created with @property (nonatomic, retain) SomeType someObject;

To clarify I have something like:

@interface SomeClass : NSObject {
   SomeType* someObject;
}

@property (nonatomic, retain) SomeType* someObject;

@end

I have noticed I get EXC_BAD ACCESS sometimes when I use the property without self and it seems quite random. When I use self my program acts as it should be. I don’t get any compiler errors or warnings when I skip self so I guess it is somehow valid syntax?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(4

傲影 2024-10-22 08:12:22

self.someObject = someOtherObject 使用该属性。属性为您生成 setter 和 getter。在您的例子中,您为属性赋予了 retain 属性,这意味着通过此属性设置的对象将自动接收 retain 消息,该消息会将其保留计数增加 1。此外,还会向成员变量的旧值发送释放消息,从而减少其保留计数。

当对象的保留计数达到 0 时,对象将被释放。如果您尝试访问已释放的对象(例如,如果您尝试过于频繁地释放它),则会收到 EXC_BAD_ACCESS 异常。

对于您的情况:

SomeOtherObject *soo = [[SomeOtherObject alloc] init]; //retain count: 1
self.someObject = soo; //soo's retain count is now 2
[soo release]; //soo's retain count is 1 again, as self still uses it.
[self doSomethingWithSoo];

但是,如果您不使用 setter,则不得释放 soo

SomeOtherObject *soo = [[SomeOtherObject alloc] init]; //retain count: 1
someObject = soo; //soo's retain count is still  1
[soo release]; //soo's retain count is 0, it will be deallocated
[self doSomethingWithSoo]; //will fail with an EXC_BAD_ACCESS exception, as soo does not exist anymore.

self.someObject = someOtherObject makes use of the property. Properties generate setters and getters for you. In your case, you gave the retain attribute to the property, which means that an object set via this property will automatically receive a retain message which increases its retain count by 1. Additionally, the old value of the member variable is sent a release message which decreases its retain count.

Obects are being deallocated, when their retain count reaches 0. You get an EXC_BAD_ACCESS ecxeption if you try to access a deallocated object (e.g. if you try to release it too often).

In your case:

SomeOtherObject *soo = [[SomeOtherObject alloc] init]; //retain count: 1
self.someObject = soo; //soo's retain count is now 2
[soo release]; //soo's retain count is 1 again, as self still uses it.
[self doSomethingWithSoo];

However, if you do not use the setter, you must not release soo.

SomeOtherObject *soo = [[SomeOtherObject alloc] init]; //retain count: 1
someObject = soo; //soo's retain count is still  1
[soo release]; //soo's retain count is 0, it will be deallocated
[self doSomethingWithSoo]; //will fail with an EXC_BAD_ACCESS exception, as soo does not exist anymore.
岁月打碎记忆 2024-10-22 08:12:22

属性只是访问数据的一种便捷方式。因此,当您声明属性 @property (nonatomic, keep) SomeType* someObject; 时这意味着在访问期间将合成 2 个方法:

getter:

-(SomeType*) someObject {
   return someObject;
}

setter

-(void) setSomeObject:(SomeType*) obj {
   [someObject release];
   someObject = [obj retain];
}

因此,属性和 ivars 之间的主要区别在于属性动态创建 setter/getter 方法(并且您可以覆盖它们)。但是当您编写 someObject = new_val 时,您只是将引用复制到内存位置。除了一条汇编指令外,没有进行任何其他工作。

还有一件事要提:原子和非原子。
使用原子,合成的 setter/getter 将确保始终从 getter 返回整个值或由 setter 设置整个值,而不管任何其他线程上的 setter 活动如何。也就是说,如果线程 A 位于 getter 中间,而线程 B 调用 setter,则实际可行的值(很可能是自动释放的对象)将返回给 A 中的调用者。

在非原子中,没有这样的保证制成。因此,非原子比原子要快得多。

编辑:所以如果你有一些变量,可以从不同的线程访问或/并且必须完成一些额外的工作(例如保留,引发一些标志......),那么你的选择就是属性。但有时您有一个经常访问的变量,并且通过属性访问可能会导致很大的开销,因为处理器必须执行更多操作来合成和调用方法。

Properties are just a convenient way to access the data. So when you are declaring the property @property (nonatomic, retain) SomeType* someObject; this means that during access there would be synthesized 2 methods:

getter:

-(SomeType*) someObject {
   return someObject;
}

setter

-(void) setSomeObject:(SomeType*) obj {
   [someObject release];
   someObject = [obj retain];
}

So the main difference between properties and ivars is that properties dynamically creating the setter/getter methods (and you can override them). But when you're writing someObject = new_val, you're just copying the reference to the memory location. No additional work is done there except one assembly instruction.

There is one more thing to mention: atomic and nonatomic.
With atomic, the synthesized setter/getter will ensure that a whole value is always returned from the getter or set by the setter, regardless of setter activity on any other thread. That is, if thread A is in the middle of the getter while thread B calls the setter, an actual viable value -- an autoreleased object, most likely -- will be returned to the caller in A.

In nonatomic, no such guarantees are made. Thus, nonatomic is considerably faster than atomic.

Edit: so if you have some variable, that is accessed from different threads or/and some additional work has to be done (e.g. retain, raise some flags ...), then your choice is property. But sometimes you have a variable, that is accessed very often and access via property can lead to a big overhead, because processor has to perform much more operations to synthesize and call method.

失退 2024-10-22 08:12:22

这都是关于内存管理的。

您的类属性 someObject 已在 .h / .m 文件中生成带有注释 @property / @synthsize 的访问器。

当您使用 someObject 访问属性时,您可以直接访问该属性。当您访问 self.someObject 时,您正在调用您的访问器 [self someObject] ,它会为您处理内存管理。

因此,当您需要分配类属性时,执行 self.someObject = someOtherObject; 会更干净,因为您使用 setter 并且不必关心释放和保留。当您的 setter 是使用 @property (nonatomic, keep) 生成的时,它会为您处理保留问题。

It's all about memory management.

Your class property someObject have generated accessors with annotation @property / @synthsize in your .h / .m files.

When you are accessing you property with someObject, you directly access the property. When you are accessing self.someObject you are calling your accessor [self someObject] whitch take care of memory management for you.

So when you need to assign a class property it's cleaner to do self.someObject = someOtherObject; because you use the setter and does not have to take care about releasing and retaining. When your setter is generated with @property (nonatomic, retain) so it will take care about retaining for you.

绮烟 2024-10-22 08:12:22

两者之间的区别是:

1)当你不使用“self”时。您将结果直接分配给成员变量。

2)当你使用“自我”时。您正在对该属性调用 setter 方法。与 [self setMyObject:...] 相同;

因此,在 self.myobject 的情况下,它会保留其保留,而在其他情况下(没有 self),如果您不使用 alloc,那么它将被视为自动释放的对象。

在大多数情况下,您会发现您想要使用“self.”,除非在对象初始化期间。

顺便说一句,您还可以使用 self.someObject = [someOtherObject keep] 来增加保留计数器

The difference between the two is:

1) when you do not use "self." you are assigning the result directly to the member variable.

2) when you are using "self." you are calling the setter method on that property. It is the same as [self setMyObject:...];

so in case of self.myobject, it keeps its retain, and in other case, (without self), if you are not using alloc, then it will be treated as autoreleased object.

In most cases you will find you want to use "self.", except during the initialization of the object.

By the way, you can also use self.someObject = [someOtherObject retain] to increase retain counter

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