i was reading this code, where setRegions
is called after RootViewController
is released : i find it a bit strange : does it mean RootViewController
is still accessible, even if it was released and self.navigationController
"owns" it ?
我正在阅读这段代码,其中在RootViewController发布后调用setRegions:我发现它有点奇怪:它是否仍然可以访问RootViewController,即使它已经发布并且self.navigationController“拥有”它?
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the navigation and view controllers
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
[aNavigationController release];
[rootViewController release];
[rootViewController setRegions:[Region knownRegions]];
// Configure and display the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
Thanks
3 个解决方案
#1
4
This is bad code.
这是糟糕的代码。
An object should retain another object for as long as it cares about it. And in this case that rule is broken. The rootViewController
is released, and then as you note, a method is called on it. This can be dangerous.
只要对象关心它,它就应该保留另一个对象。在这种情况下,该规则被打破。 rootViewController被释放,然后在你注意到的时候,就会调用一个方法。这可能很危险。
In this case, it works. This is because rootViewController
is passed to another object, which retains it. So when we release it, it still has a positive retain count and is not deallocated. So our reference to it still works, and methods called on it work fine.
在这种情况下,它的工作原理。这是因为rootViewController被传递给另一个保留它的对象。因此,当我们发布它时,它仍然具有正保留计数并且不会被释放。所以我们对它的引用仍然有效,并且调用它的方法工作正常。
But lets say some implementation changed and initWithRootViewController:
now no longer retained it's argument for some reason (an assumption you can't really make all the time). Suddenly this all crashes because rootViewController
gets deallocated.
但是让我们说一些实现发生了变化,并且initWithRootViewController:由于某些原因现在不再保留它的参数(假设你不能真正做到这一点)。突然之间这一切都崩溃了,因为rootViewController被取消分配。
To fix this funk, you just need to move [rootViewController release];
to after the last useful reference of that object in this function. Your code then becomes more robust and more correct.
要解决这个问题,你只需要移动[rootViewController release];在此函数中该对象的最后一个有用引用之后。然后您的代码变得更健壮,更正确。
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the navigation and view controllers
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
[rootViewController setRegions:[Region knownRegions]];
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
// Release temporary objects since we've now sent them to other other objects
// which may or may not retain them (we don't really care which here)
[aNavigationController release];
[rootViewController release];
// Configure and display the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
Last thing to note: release
and dealloc
are very different things. release
does not necessarily destroy objects. It simply decrements the retain
count by one. And if that retain
count ever gets to zero, only then is the object is deallocated. So this code works because a release
happens but without triggering a dealloc
.
最后要注意的是:release和dealloc是非常不同的东西。释放不一定会破坏对象。它只是将保留计数减1。如果保留计数永远为零,那么只有对象被释放。所以这段代码可以正常运行,因为发布了但没有触发dealloc。
#2
1
The above is very dangerous code. It might happen to work, but it's just getting lucky. You should never access a variable after you have released it. In fact, it is best practice to immediately set variables to nil
after releasing them if they don't immediately go out of scope. Some people only do this in Release mode, and so create a macro like:
以上是非常危险的代码。它可能会发生作用,但它只是运气好。在释放变量后,永远不应该访问变量。实际上,如果不立即超出范围,最好在释放后立即将变量设置为nil。有些人只在发布模式下执行此操作,因此创建一个宏,如:
#ifdef DEBUG
#define RELEASE(x) [x release];
#else
#define RELEASE(x) [x release]; x = nil;
#endif
The reason for this is to help catch bugs in debug mode (by having a crash rather than just a silent nil
pointer), while being a bit safer in release mode.
这样做的原因是为了帮助捕获调试模式中的错误(通过崩溃而不仅仅是一个静默的nil指针),同时在发布模式下更安全一些。
But in any case, you should never access a variable after you've released it.
但无论如何,在发布变量之后,永远不应该访问变量。
#3
1
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
(objectA created, retain count is 1, rootViewController points to it)
(objectA创建,保留计数为1,rootViewController指向它)
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
(objectB created, retain count is 1, aNavigationController points to it) (objectA retain count is 2 now, both rootViewController and some property in self.aNavigationController point to it)
(objectB创建,保留计数为1,aNavigationController指向它)(objectA保留计数现在为2,rootViewController和self.aNavigationController中的某些属性指向它)
self.navigationController = aNavigationController;
(objectB retain count is 2 now, both aNavigationController and self.navigationController point to it; assuming self.navigationController is a retain property)
(objectB保留计数现在是2,aNavigationController和self.navigationController都指向它;假设self.navigationController是一个retain属性)
[aNavigationController release];
(objectB retain count is 1 now, however, both aNavigationController and self.navigationController point to it)
(objectB保留计数现在为1,但是,aNavigationController和self.navigationController都指向它)
[rootViewController release];
(objectA retain count is 1 now, however, both rootViewController and some property in self.aNavigationController point to it)
(objectA保留计数现在为1,但是,root.ConNovigationController和self.aNavigationController中的某些属性指向它)
[rootViewController setRegions:[Region knownRegions]];
(use rootViewController to access objectA) (This is not good)
(使用rootViewController访问objectA)(这不好)
Following is my recommended way:
以下是我推荐的方式:
RootViewController *rootViewController = [[[RootViewController alloc] initWithStyle:UITableViewStylePlain] autorelease];
[rootViewController setRegions:[Region knownRegions]];
UINavigationController *aNavigationController = [[[UINavigationController alloc] initWithRootViewController:rootViewController] autorelease];
self.navigationController = aNavigationController;
#1
4
This is bad code.
这是糟糕的代码。
An object should retain another object for as long as it cares about it. And in this case that rule is broken. The rootViewController
is released, and then as you note, a method is called on it. This can be dangerous.
只要对象关心它,它就应该保留另一个对象。在这种情况下,该规则被打破。 rootViewController被释放,然后在你注意到的时候,就会调用一个方法。这可能很危险。
In this case, it works. This is because rootViewController
is passed to another object, which retains it. So when we release it, it still has a positive retain count and is not deallocated. So our reference to it still works, and methods called on it work fine.
在这种情况下,它的工作原理。这是因为rootViewController被传递给另一个保留它的对象。因此,当我们发布它时,它仍然具有正保留计数并且不会被释放。所以我们对它的引用仍然有效,并且调用它的方法工作正常。
But lets say some implementation changed and initWithRootViewController:
now no longer retained it's argument for some reason (an assumption you can't really make all the time). Suddenly this all crashes because rootViewController
gets deallocated.
但是让我们说一些实现发生了变化,并且initWithRootViewController:由于某些原因现在不再保留它的参数(假设你不能真正做到这一点)。突然之间这一切都崩溃了,因为rootViewController被取消分配。
To fix this funk, you just need to move [rootViewController release];
to after the last useful reference of that object in this function. Your code then becomes more robust and more correct.
要解决这个问题,你只需要移动[rootViewController release];在此函数中该对象的最后一个有用引用之后。然后您的代码变得更健壮,更正确。
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Create the navigation and view controllers
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
[rootViewController setRegions:[Region knownRegions]];
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
self.navigationController = aNavigationController;
// Release temporary objects since we've now sent them to other other objects
// which may or may not retain them (we don't really care which here)
[aNavigationController release];
[rootViewController release];
// Configure and display the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}
Last thing to note: release
and dealloc
are very different things. release
does not necessarily destroy objects. It simply decrements the retain
count by one. And if that retain
count ever gets to zero, only then is the object is deallocated. So this code works because a release
happens but without triggering a dealloc
.
最后要注意的是:release和dealloc是非常不同的东西。释放不一定会破坏对象。它只是将保留计数减1。如果保留计数永远为零,那么只有对象被释放。所以这段代码可以正常运行,因为发布了但没有触发dealloc。
#2
1
The above is very dangerous code. It might happen to work, but it's just getting lucky. You should never access a variable after you have released it. In fact, it is best practice to immediately set variables to nil
after releasing them if they don't immediately go out of scope. Some people only do this in Release mode, and so create a macro like:
以上是非常危险的代码。它可能会发生作用,但它只是运气好。在释放变量后,永远不应该访问变量。实际上,如果不立即超出范围,最好在释放后立即将变量设置为nil。有些人只在发布模式下执行此操作,因此创建一个宏,如:
#ifdef DEBUG
#define RELEASE(x) [x release];
#else
#define RELEASE(x) [x release]; x = nil;
#endif
The reason for this is to help catch bugs in debug mode (by having a crash rather than just a silent nil
pointer), while being a bit safer in release mode.
这样做的原因是为了帮助捕获调试模式中的错误(通过崩溃而不仅仅是一个静默的nil指针),同时在发布模式下更安全一些。
But in any case, you should never access a variable after you've released it.
但无论如何,在发布变量之后,永远不应该访问变量。
#3
1
RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
(objectA created, retain count is 1, rootViewController points to it)
(objectA创建,保留计数为1,rootViewController指向它)
UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
(objectB created, retain count is 1, aNavigationController points to it) (objectA retain count is 2 now, both rootViewController and some property in self.aNavigationController point to it)
(objectB创建,保留计数为1,aNavigationController指向它)(objectA保留计数现在为2,rootViewController和self.aNavigationController中的某些属性指向它)
self.navigationController = aNavigationController;
(objectB retain count is 2 now, both aNavigationController and self.navigationController point to it; assuming self.navigationController is a retain property)
(objectB保留计数现在是2,aNavigationController和self.navigationController都指向它;假设self.navigationController是一个retain属性)
[aNavigationController release];
(objectB retain count is 1 now, however, both aNavigationController and self.navigationController point to it)
(objectB保留计数现在为1,但是,aNavigationController和self.navigationController都指向它)
[rootViewController release];
(objectA retain count is 1 now, however, both rootViewController and some property in self.aNavigationController point to it)
(objectA保留计数现在为1,但是,root.ConNovigationController和self.aNavigationController中的某些属性指向它)
[rootViewController setRegions:[Region knownRegions]];
(use rootViewController to access objectA) (This is not good)
(使用rootViewController访问objectA)(这不好)
Following is my recommended way:
以下是我推荐的方式:
RootViewController *rootViewController = [[[RootViewController alloc] initWithStyle:UITableViewStylePlain] autorelease];
[rootViewController setRegions:[Region knownRegions]];
UINavigationController *aNavigationController = [[[UINavigationController alloc] initWithRootViewController:rootViewController] autorelease];
self.navigationController = aNavigationController;