Objective c Cocoa示例-为什么不需要保留或发布消息

Objective c Cocoa示例-为什么不需要保留或发布消息,objective-c,cocoa,memory-management,alloc,Objective C,Cocoa,Memory Management,Alloc,我不熟悉Objective-C和cocoa。在Apple为Cocoa提供的示例中,有一个令人困惑的内存管理示例: 假设您想要实现一种方法来重置计数器。你有两个选择。第一个实现使用alloc创建NSNumber实例,因此您可以通过发布来平衡这一点 第二个使用方便的构造函数创建新的NSNumber对象。因此,不需要保留或释放消息 我不确定为什么创建对象时使用“new”而不是“alloc&init”不需要保留/释放。我的理解是,两者都在做相同的事情,除了“alloc&init”我们可以使用自定义检查和

我不熟悉Objective-C和cocoa。在Apple为Cocoa提供的示例中,有一个令人困惑的内存管理示例:

假设您想要实现一种方法来重置计数器。你有两个选择。第一个实现使用alloc创建NSNumber实例,因此您可以通过发布来平衡这一点

第二个使用方便的构造函数创建新的NSNumber对象。因此,不需要保留或释放消息

我不确定为什么创建对象时使用“new”而不是“alloc&init”不需要保留/释放。我的理解是,两者都在做相同的事情,除了“alloc&init”我们可以使用自定义检查和初始化


非常感谢。

按照惯例,所有以“alloc”或“copy”或“new”开头的方法都会将保留计数增加1

所有其他方法都不会更改保留计数。由于“numberWithInteger”不是以“alloc”、“copy”或“new”开头,因此它返回一个保留计数为0的对象。但它没有立即将其设置为0(这永远不会起作用),而是使用“自动释放池”将保留计数设置为1,然后计划在将来某个时间点将其降至0(通常在事件循环空闲时,但您可以手动使其更快发生)

当然,alloc/copy/new命名约定的唯一例外是实际的“retain”和“release”以及“autorelease”方法,它们增加/减少了保留计数,或者安排在以后减少

它不是一种语言特性,只是一种编码实践。每个以“alloc”、“copy”和“new”开头的方法都将retain设置为1,其他所有方法都将其设置为1,但计划稍后将其删除为0

当然,如果您使用的是ARC,并且您绝对应该使用ARC,那么您就不必担心这些问题,因为编译器将找到使用该对象的最后一行代码,并在其后面插入一行代码以释放内存。这会导致更快的代码,因为自动释放机制有点慢,有时会使用太多的RAM


启用ARC时,这些规则均不适用。编译器忽略所有内存管理代码(或告诉您将其删除),并编写自己的代码。这不是真正的垃圾收集,它只是由Xcode生成的手动内存管理,而不是手工编写的。

按照惯例,所有以“alloc”、“copy”或“new”开头的方法都会将保留计数增加1

所有其他方法都不会更改保留计数。由于“numberWithInteger”不是以“alloc”、“copy”或“new”开头,因此它返回一个保留计数为0的对象。但它没有立即将其设置为0(这永远不会起作用),而是使用“自动释放池”将保留计数设置为1,然后计划在将来某个时间点将其降至0(通常在事件循环空闲时,但您可以手动使其更快发生)

当然,alloc/copy/new命名约定的唯一例外是实际的“retain”和“release”以及“autorelease”方法,它们增加/减少了保留计数,或者安排在以后减少

它不是一种语言特性,只是一种编码实践。每个以“alloc”、“copy”和“new”开头的方法都将retain设置为1,其他所有方法都将其设置为1,但计划稍后将其删除为0

当然,如果您使用的是ARC,并且您绝对应该使用ARC,那么您就不必担心这些问题,因为编译器将找到使用该对象的最后一行代码,并在其后面插入一行代码以释放内存。这会导致更快的代码,因为自动释放机制有点慢,有时会使用太多的RAM


启用ARC时,这些规则均不适用。编译器忽略所有内存管理代码(或告诉您将其删除),并编写自己的代码。这不是实际的垃圾收集,它只是由Xcode生成的手动内存管理,而不是手工编写的。

第二个示例返回一个自动释放的对象。方便构造函数的代码可能是这样的,至少在复制功能时是这样的

+ (NSNumber *)numberWithInteger:(NSInteger)integer
{
    NSNumber *number = [[NSNumber alloc] initWithInteger:integer];
    return [number autorelease];
}
自动释放是一种延迟向对象发送释放方法的方法,同时不将对象的所有权委托给构造函数的调用方。这是一个重要的概念,因为命名约定要求您不返回对象的所有权,除非您的方法以
copy
new
alloc
retain
开头。但是,由于无法返回一个拥有的对象,因此必须在便利构造函数中对其调用
release
,这将导致返回一个解除分配的对象。因此,autorelease允许您将一个未拥有的对象返回给调用方,调用方稍后将收到一个实际的释放方法(当当前autorelease池耗尽时)

Autorelease方法收集在所谓的Autorelease池中,这是线程本地准链表(它们不是作为链表实现的,但它们确实像以前一样工作),只收集Autorelease对象。可以通过调用多次将对象添加到它们中,对于它们接收到的每个
autorelease
方法一次。当池被排空或销毁时,它包含的所有对象都将收到一条
release
消息。默认情况下,系统将至少在主线程上为您提供一个自动释放池,但您可以使用此代码创建自己的自动释放池(如果您仔细查看,每个主方法中也会用到此代码):


第二个示例返回一个自动释放的对象。方便构造函数的代码可能是这样的,至少在复制功能时是这样的

+ (NSNumber *)numberWithInteger:(NSInteger)integer
{
    NSNumber *number = [[NSNumber alloc] initWithInteger:integer];
    return [number autorelease];
}
Autorelease是一种延迟向对象发送释放方法的方法,而n
+ (NSNumber *)numberWithInteger:(NSInteger)integer
{
    NSNumber *number = [[NSNumber alloc] initWithInteger:integer];
    return [number autorelease];
}
@autoreleaspool
{
    [foo autorelease]; // foo will receive a `release` method at the closing brace    
}
NSDate *date = [NSDate new]; // I will have to send -release at some point
NSDate *date = [NSDate date]; // I won't have to send -release
// But this object will be dealloced soon
// so if I want it to stick around, I will need to retain it
CGContextRef context = UIGraphicsGetCurrentContext(); // I won't have to release this context
CGImageRef result = CGBitmapContextCreateImage(context); // I will have to release this image
/* ... */
CGRelease(result);