我可以在设置viewController时跳过创建单独的指针吗?

时间:2011-05-05 22:27:55

标签: iphone objective-c pointers viewcontroller

为什么我需要创建一个指针来分配内存然后立即释放它?

换句话说,我不能这样做:

self.viewController = [[HelloWorldViewController alloc] initWithNibName:@"HelloWorldViewController" bundle:[NSBundle mainBundle]];

而不是:

HelloWorldViewController *newViewController = [[HelloWorldViewController alloc] initWithNibName:@"HelloWorldViewController" bundle:[NSBundle mainBundle]];
self.viewController = newViewController;
[newViewController release];

[编辑]

为我的问题提供更广泛的背景:(在@interface的@interface HelloWorldAppDelegate:NSObject< UIApplicationDelegate>中)

@synthesize window=_window;
@synthesize viewController=_viewController;

...

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    HelloWorldViewController *newViewController = [[HelloWorldViewController alloc] initWithNibName:@"HelloWorldViewController" bundle:[NSBundle mainBundle]];
    self.viewController = newViewController;
    [newViewController release];

    self.window.rootViewController = self.viewController;

    [self.window makeKeyAndVisible];
    return YES;
}

...

- (void)dealloc
{
    [_window release];
    [_viewController release];
    [super dealloc];
}

所以,在didFinish ...方法中,我可以使用上面提供的短版本,还是会泄漏?

[第二编辑]

似乎我无法提供足够的信息。我总是犹豫要发一大堆代码。 我在HelloWorldAppDelegate.h中得到了这个:

@property (nonatomic, retain) IBOutlet HelloWorldViewController *viewController;

所以,如果我错了,请纠正我。鉴于头文件中viewController的声明,如果我使用快捷方法(在上面的第一个代码片段中),程序将泄漏。对象计数器由alloc增加一次,然后由retain增加第二次,然后在释放时递减一次,在指针引用计数器上产生+1的净值。

2 个答案:

答案 0 :(得分:3)

必须释放你分配的对象,否则你最终会发生内存泄漏。对self.viewController(可能)的分配保留了新分配的HelloWorldViewController,因此您在对象上有两个“声明” - 一个来自您对alloc的呼叫,另一个来自retain,但您实际上不会再以newViewController名称使用它,因此您可以通过调用release来放弃该特定声明。

使用temp变量的“long”形式实际上是执行此操作的正确方法。在设置之后立即将release发送到属性访问结果:[self.viewController release];很可能会起作用,但是is incorrect(并且会为最近的LLVM版本生成编译器警告)。

也可以这样做:

self.viewController = [[[HelloWorldViewController alloc] initWithNibName:@"HelloWorldViewController" 
                                                                  bundle:[NSBundle mainBundle]]
                          autorelease];

其中说“我已经创建了这个东西以便简单地使用它,但我不会在这个直接调用堆栈之外需要它,所以请继续以后为我发布它。”

如果viewController不是retain属性,那么所有这些都没有实际意义,并且不应向新视图控制器发送release ,因为它会在您使用之前被解除分配。

更新:您的扩展问题不会改变任何内容*。如果在release超出范围之前没有发送newViewController,则最终会发生泄漏。**其工作方式是,需要的任何对象(A,B,C)使用对象X,因此关心保持它,将retain发送给X.当你alloc一个对象时,假设你需要使用它。当A,B或C中的任何一个不再需要X时,它会向{X}发送release,从而说“X可以被解除分配并且不会影响我”。您需要在具有该号码的对象上平衡您所声明的声明数量(使用retainalloccopy / mutableCopynew)你所做的放弃(通过发送releaseautorelease),否则你手上会有泄密或意外解除分配。

我现在要给你一个文档的链接,但不要生气,这只是你需要阅读和内化的一个页面:The Fundamental Rule of Cocoa Memory Management


*实际上,你遗漏了唯一可以改变答案的部分,即你的

@property () HelloWorldViewController * viewController;

声明。如果在这些括号中显示“保留”,则在设置此属性时,您的应用委托会将retain发送到传递的对象。如果它显示“assign”,或者括号不在那里,那么就像我说的那样,你不应该向该对象发送release

**注意任何看过的小伙伴:你当然可以在某个时候向release发送viewController 两次,但这比泄漏更糟糕

答案 1 :(得分:2)

是的,你可以这样做。除非您必须释放self.viewController,以便在代码段末尾保留计数为1。

让我们算一算。在分配时,释放计数为1.将其分配给self.viewController(假设它是具有retain行为的属性)将其增加到2。在第二个片段的末尾释放它使它再次成为1。这个想法是你将在当前类的dealloc中完全释放它,无论是什么。

唯一的缺点是释放一个对象变量假定你完成了它,在这里你必须去,释放self.viewController但稍后使用它。有点臭。