当没有dealloc方法时,我应该自动释放保留的属性/实例变量吗?

时间:2013-10-28 17:31:29

标签: objective-c memory-management

我正在学习内存管理一段时间。阅读Apple的内存管理指南以及其他一些作者的书/博客/论文/帖子。

令我感到困惑的是我是否应该写:

nameOfMySynthesizedProperty = [[NSObject alloc] init]; // version 1

nameOfMySynthesizedProperty = [[[NSObject alloc] init] autorelease]; // version 2

在示例项目中,使用手动内存管理,没有dealloc方法,版本1用于所有类属性/ ivars。有时某些属性甚至没有合成,但使用了它的吸气剂,

这些都没有在我读过的那些教程/指南中讲授,但是样本项目顺利进行而没有崩溃......

任何人都可以给我一些启示......

更新1

示例项目中使用了手动内存管理。

更新2

另一个例子

AppDelegate.h

#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
}
@property (nonatomic, retain) UIWindow *window;
@property (nonatomic, retain) UIViewController *viewController;
@end

AppDelegate.m

@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    // To be inserted with the following choices of code
}
@end

AppDelegate.m - &gt;内-(BOOL)application:application didFinishLaunchingWithOptions:方法,以下哪项适用于初始化self.window.rootViewController? (使用手动存储器管理。使用Xcode 5。)

版本1

self.window.rootViewController = [[UIViewController alloc] init];
self.viewController = [[[UIViewControllerDrawer alloc]init] autorelease];
self.window.rootViewController = self.viewController;

第2版

self.window.rootViewController = [[[UIViewController alloc] init] autorelease];
self.viewController = [[[UIViewControllerDrawer alloc]init] autorelease];
self.window.rootViewController = self.viewController;

第3版

self.viewController = [[[UIViewControllerDrawer alloc]init] autorelease];
self.window.rootViewController = self.viewController;

我知道window是一个属性(并且它的实例变量也被命名为window)。但是window.rootViewController是一个实例变量吗?实验结果显示版本3正在运行,版本1和版本2都崩溃。

3 个答案:

答案 0 :(得分:6)

都不是。你应该使用ARC。今天很少有理由使用手动内存管理。 (理解 ARC如何应用内存管理规则很有用,但直接使用它是个坏主意。)

如果您绝对必须使用手动内存管理,那么您通常也不应该通过这种方式直接访问ivars。除initdealloc外,您应该这样做:

self.property = [[[NSObject alloc] init] autorelease];

init中,你应该这样做:

_property = [[NSObject alloc] init];

在任何一种情况下(但只有当您使用手动内存管理时,您不应该这样做),您需要dealloc中的以下内容:

[_property release];
_property = nil;

精确规则的最佳参考是Memory Management Policy

但我不能强调:如果你甚至问这些问题,你应该使用ARC。如果您不必问这些问题,您应该已经知道为什么要使用ARC。如果您遇到某种非常专业的问题(例如在32位OS X上运行),那么您可能已经知道规则以及如何正确应用它们。

如果您遇到手动内存管理的现有代码,则应使用“编辑&gt;重构&gt;转换为Objective-C ARC ...”,这将为您解决此问题。

答案 1 :(得分:3)

这里有几个不同的问题,我会尽力解决这些问题。

的dealloc

总有一个dealloc方法,你可能没有覆盖它,但它至少是由NSObject实现的。您几乎总是需要在子类中重写此方法以释放对象ivars。使用ARC,您只需将它们设置为nil,但在MRC中,您需要向任何保留或分配的变量发送释放消息。

当对象保持计数达到0时,会自动调用dealloc方法。

使用自动释放

您发布的代码存在一个问题,即您将自动释放的对象分配给ivar,并且在自动释放池耗尽后该对象将停止有效(通常是事件循环的开始)。

当您不想保留对象时使用自动释放,但它需要继续使用该方法的调用者。当一个方法返回一个对象时,该对象应该始终按照objective-c ownership rules自动释放,但这并不意味着你总是需要自己发送自动释放消息。如果您要返回的对象是自动释放的,那么您只需返回该对象。

你分配的任何东西都会有一个保留计数为1,你需要在某个时候释放它或者你有泄漏。

@synthesize

您不需要显式合成属性。编译器会为你合成它们。你必须注意声明属性的方式(并在你自己实现的情况下实现),以了解分配给属性是增加保留计数,复制对象还是进行简单的赋值。我在您更新的问题中看到您的意思是self.property = [[[NSObject alloc] init] autorelease],因为属性被声明为保留。你可以做_property = [[NSObject alloc] init],这是相当典型的用法。在直接使用ivars之前,您需要了解属性周围的语义(例如,通过分配给ivar不会触发KVO通知)。

ARC vs MRC

关于MRC与ARC的关系。很多人声称你应该总是使用ARC(如果你可以帮助它),而不是MRC。重要的是要了解不正确地使用ARC会导致代码明显变慢。我见过“ARC”代码,它对循环中的临时值使用隐式强引用,导致大量不必要的保留释放调用。理解MRC对于编写好的ARC代码IMO是必不可少的,不要让这些人阻止你学习内存管理的细节。

答案 2 :(得分:2)

如果从以alloc / init,copy,mutableCopy或new开头的方法获取对象实例,则您拥有它并负责在完成后释放它。否则,您不负责发布它。如果你想保留一个非拥有的对象,你必须保留它,然后在你完成后释放它。出于这些规则的目的,自动释放对象与释放对象相同。自动释放的对象将在未来的某个时间点释放(在大多数情况下,当前运行循环结束)。

在你的问题中,你直接设置了一个ivar。你不希望ivar指向的对象从你身下消失,所以你应该自动释放它。除非有问题的行在您的类-init方法中,否则您应该使用setter,并在将对象传递给setter(self.nameOfMySynthesizedProperty = [[[NSObject alloc] init] autorelease];)之前自动释放该对象。这样,setter(假设属性为strong / retain处理保留对象,并且如果稍后再次将其设置为另一个对象,也将处理释放它。

最后,我欣赏并欣赏您的学习手册内存管理。我认为Objective-C程序员理解它很重要。因此,如果这只是一个学习练习,请继续学习。但是,对于编写实际代码,你应该使用ARC,这使整个问题基本上没有实际意义。