我正在学习内存管理一段时间。阅读Apple的内存管理指南以及其他一些作者的书/博客/论文/帖子。
令我感到困惑的是我是否应该写:
nameOfMySynthesizedProperty = [[NSObject alloc] init]; // version 1
或
nameOfMySynthesizedProperty = [[[NSObject alloc] init] autorelease]; // version 2
在示例项目中,使用手动内存管理,没有dealloc
方法,版本1用于所有类属性/ ivars。有时某些属性甚至没有合成,但使用了它的吸气剂,
这些都没有在我读过的那些教程/指南中讲授,但是样本项目顺利进行而没有崩溃......
任何人都可以给我一些启示......
示例项目中使用了手动内存管理。
另一个例子
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都崩溃。
答案 0 :(得分:6)
都不是。你应该使用ARC。今天很少有理由使用手动内存管理。 (理解 ARC如何应用内存管理规则很有用,但直接使用它是个坏主意。)
如果您绝对必须使用手动内存管理,那么您通常也不应该通过这种方式直接访问ivars。除init
和dealloc
外,您应该这样做:
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方法,你可能没有覆盖它,但它至少是由NSObject实现的。您几乎总是需要在子类中重写此方法以释放对象ivars。使用ARC,您只需将它们设置为nil,但在MRC中,您需要向任何保留或分配的变量发送释放消息。
当对象保持计数达到0时,会自动调用dealloc方法。
您发布的代码存在一个问题,即您将自动释放的对象分配给ivar,并且在自动释放池耗尽后该对象将停止有效(通常是事件循环的开始)。
当您不想保留对象时使用自动释放,但它需要继续使用该方法的调用者。当一个方法返回一个对象时,该对象应该始终按照objective-c ownership rules自动释放,但这并不意味着你总是需要自己发送自动释放消息。如果您要返回的对象是自动释放的,那么您只需返回该对象。
你分配的任何东西都会有一个保留计数为1,你需要在某个时候释放它或者你有泄漏。
您不需要显式合成属性。编译器会为你合成它们。你必须注意声明属性的方式(并在你自己实现的情况下实现),以了解分配给属性是增加保留计数,复制对象还是进行简单的赋值。我在您更新的问题中看到您的意思是self.property = [[[NSObject alloc] init] autorelease]
,因为属性被声明为保留。你可以做_property = [[NSObject alloc] init]
,这是相当典型的用法。在直接使用ivars之前,您需要了解属性周围的语义(例如,通过分配给ivar不会触发KVO通知)。
关于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,这使整个问题基本上没有实际意义。