Objective C - ARC - 何时使用@autoreleasepool
我读了一些关于 ARC 的书,看到了这个:
@interface Address : NSObject {
@public
NSString *city;
}
@end
@implementation Address
- (Address*) init: (NSString*) c {
city = c;
return self;
}
- (void) dealloc {
NSLog(@"Destroying address: %@", city);
}
@end
@interface Customer : NSObject {
NSString *name;
Address *addr;
}
@end
@implementation Customer
- (Customer*) init: (NSString*) n withAddress: (Address*) a {
//Note 1: Automatic retain on assignment
name = n;
addr = a;
return self;
}
- (void) dealloc {
NSLog(@"Destroying: %@", name);
//Note 2: Automatic release of member variables
}
@end
Customer* objectReturnTest() {
NSString * n = [[NSString alloc] initWithString: @"Billy Bob"];
Address * a = [[Address alloc] init: @"New York City"];
Customer *c = [[Customer alloc] init: n withAddress: a];
//Note 3: ARC will put the returned object in autorelease pool.
return c;
}
A couple of basic things to note here. As "Note 1" says, when an object is assigned to a variable, a call to retain is made automatically. This increments the reference count. As "Note 2" says, when an object is destroyed, all member variable objects are released for you. You no longer have to do that from the dealloc method.
Finally, when a method returns a newly created object, ARC will put the returned object in an autorelease pool. This is stated in "Note 3".
Now, let’s use the code.
int main (int argc, const char * argv[])
{
NSString * n = [[NSString alloc] initWithString: @"Johnny Walker"];
Address * a = [[Address alloc] init: @"Miami"];
Customer *c = [[Customer alloc] init: n withAddress: a];
NSLog(@"Before force release");
c = nil; //Force a release
NSLog(@"After force release");
@autoreleasepool {
Customer *c2 = objectReturnTest();
}
NSLog(@"After autorelease pool block.");
return 0;
}
The log output from this code will be:
Before force release
Destroying: Johnny Walker
After force release
Destroying: Billy Bob
Destroying address: New York City
After autorelease pool block.
Destroying address: Miami
A couple of things to note here. See how force release works. We set a variable to nil. ARC immediately releases the reference count. This causes the Customer object "Johnny Walker" to get destroyed. But, the member Address object "Miami" doesn’t get destroyed. This object gets destroyed at the very end of the main method. This is an extremely odd and non-intuitive behavior. Technically, this is not a memory leak, but, in reality member variables can pile up and take up a lot of memory. This is just as bad as memory leak.
The object return test works as expected. Customer "Billy Bob" is put in auto release pool. At the end of the @autoreleasepool block, the pool is drained and the object is released.
看着这一部分;
int main (int argc, const char * argv[])
{
NSString * n = [[NSString alloc] initWithString: @"Johnny Walker"];
Address * a = [[Address alloc] init: @"Miami"];
Customer *c = [[Customer alloc] init: n withAddress: a];
NSLog(@"Before force release");
c = nil; //Force a release
NSLog(@"After force release");
@autoreleasepool {
Customer *c2 = objectReturnTest();
}
NSLog(@"After autorelease pool block.");
return 0;
}
当他这样做时 c = nil; ca和n不应该全部被销毁吗?然而它说输出只是 n 被破坏了.. 有人可以解释为什么吗?
他说结果就像内存泄漏一样糟糕,那么如何修复呢?
最后一个问题,什么时候应该使用@autoreleaasepool?
I was reading a little about ARC and I saw this:
@interface Address : NSObject {
@public
NSString *city;
}
@end
@implementation Address
- (Address*) init: (NSString*) c {
city = c;
return self;
}
- (void) dealloc {
NSLog(@"Destroying address: %@", city);
}
@end
@interface Customer : NSObject {
NSString *name;
Address *addr;
}
@end
@implementation Customer
- (Customer*) init: (NSString*) n withAddress: (Address*) a {
//Note 1: Automatic retain on assignment
name = n;
addr = a;
return self;
}
- (void) dealloc {
NSLog(@"Destroying: %@", name);
//Note 2: Automatic release of member variables
}
@end
Customer* objectReturnTest() {
NSString * n = [[NSString alloc] initWithString: @"Billy Bob"];
Address * a = [[Address alloc] init: @"New York City"];
Customer *c = [[Customer alloc] init: n withAddress: a];
//Note 3: ARC will put the returned object in autorelease pool.
return c;
}
A couple of basic things to note here. As "Note 1" says, when an object is assigned to a variable, a call to retain is made automatically. This increments the reference count. As "Note 2" says, when an object is destroyed, all member variable objects are released for you. You no longer have to do that from the dealloc method.
Finally, when a method returns a newly created object, ARC will put the returned object in an autorelease pool. This is stated in "Note 3".
Now, let’s use the code.
int main (int argc, const char * argv[])
{
NSString * n = [[NSString alloc] initWithString: @"Johnny Walker"];
Address * a = [[Address alloc] init: @"Miami"];
Customer *c = [[Customer alloc] init: n withAddress: a];
NSLog(@"Before force release");
c = nil; //Force a release
NSLog(@"After force release");
@autoreleasepool {
Customer *c2 = objectReturnTest();
}
NSLog(@"After autorelease pool block.");
return 0;
}
The log output from this code will be:
Before force release
Destroying: Johnny Walker
After force release
Destroying: Billy Bob
Destroying address: New York City
After autorelease pool block.
Destroying address: Miami
A couple of things to note here. See how force release works. We set a variable to nil. ARC immediately releases the reference count. This causes the Customer object "Johnny Walker" to get destroyed. But, the member Address object "Miami" doesn’t get destroyed. This object gets destroyed at the very end of the main method. This is an extremely odd and non-intuitive behavior. Technically, this is not a memory leak, but, in reality member variables can pile up and take up a lot of memory. This is just as bad as memory leak.
The object return test works as expected. Customer "Billy Bob" is put in auto release pool. At the end of the @autoreleasepool block, the pool is drained and the object is released.
Looking at this part;
int main (int argc, const char * argv[])
{
NSString * n = [[NSString alloc] initWithString: @"Johnny Walker"];
Address * a = [[Address alloc] init: @"Miami"];
Customer *c = [[Customer alloc] init: n withAddress: a];
NSLog(@"Before force release");
c = nil; //Force a release
NSLog(@"After force release");
@autoreleasepool {
Customer *c2 = objectReturnTest();
}
NSLog(@"After autorelease pool block.");
return 0;
}
When he does c = nil;
shouldn't c a and n all be destroyed? Yet it says the output is only that n is destroyed..
Can someone explain why?
And he says the outcome is as bad as a memory leak, then how do you fix it?
And one last question, when should you use @autoreleaasepool?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
逐行取消
分配
Customer
实例,因为没有人保留它,因此输出为,但
n
和a
尚未被释放,因为它们仍然保留在作用域中,并且nil
尚未分配给它们。我不认为这是任何类型的内存泄漏,
你通常不需要使用@autorelasepool,除非你正在做这样的事情,
在循环期间将分配 1000000 NSString。它们将在方法返回后(实际上是在此运行循环之后)被释放,但已经消耗了太多内存。因此应该替换为
您应该阅读此内容以了解有关内存管理的更多信息
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047-CJBFBEDI
by line
a
Customer
instance is deallocated because no one is retaining it, so as a result the output isbut
n
anda
have not been deallocated because they still remain in the scope andnil
has not been assigned to them.and I don't think this is any kind of memory leak
you normally do not need to use @autorelasepool unless you are doing something like this
Than 1000000 NSString will be allocated during loop. They will be deallocated after the method returned (actually after this runloop) but already consume too much memory. Therefore should replace to
you should read this to learn more about memory management
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/uid/20000047-CJBFBEDI
名称和地址之间的明显区别在于,您为地址创建一个地址对象,为名称创建 NSString。在地址对象中它是@public。这意味着当客户被释放时,NSString 超出了范围,但不是地址对象,它仍然会记住当您释放客户时给@public NSString *city 的地址。
因此,当您调用地址的公共值时,它仍然存在,但名称的 NSString 不存在。要解决此问题,您可以删除地址对象的接口,这会释放这两个值,或者为名称创建一个接口而不是使用 NSString。
The obvious differense between name and address is that you create an Address Object for address and NSString for name. In the address object it is @public. This meeas the NSString is out of scope when customer is released, but not the address object, it will still remember the address given to the @public NSString *city when you release customer.
So when you call this public value for address it is still there, but not the NSString for name. To fix this you either remove the interface of Address Object, which releases both values or you create one interface for name instead of using NSString.