【问题标题】:call a method after the object is released?释放对象后调用方法?
【发布时间】:2012-04-04 01:26:35
【问题描述】:

我正在阅读这段代码,其中setRegionsRootViewController 被释放后被调用:我觉得有点奇怪:这是否意味着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];
}

谢谢

【问题讨论】:

    标签: objective-c uinavigationcontroller release


    【解决方案1】:

    这是错误的代码。

    一个对象应该保留另一个对象,只要它关心它。在这种情况下,这条规则被打破了。 rootViewController 被释放,然后如您所见,在其上调用了一个方法。这可能很危险。

    在这种情况下,它可以工作。这是因为rootViewController 被传递给另一个对象,该对象保留它。所以当我们释放它时,它仍然有一个正的保留计数并且没有被释放。所以我们对它的引用仍然有效,并且调用它的方法也能正常工作。

    但是假设一些实现发生了变化,initWithRootViewController: 现在由于某种原因不再保留它的论点(你不能一直做这个假设)。突然这一切都崩溃了,因为 rootViewController 被释放了。

    要解决这个问题,您只需将[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];
    }
    

    最后要注意的是:releasedealloc 是非常不同的东西。 release 不一定会破坏对象。它只是将retain 计数减一。如果 retain 计数变为零,只有在之后对象才会被释放。所以这段代码有效,因为发生了release,但没有触发dealloc

    【讨论】:

      【解决方案2】:

      以上是非常危险的代码。它可能会起作用,但它只是变得幸运。释放变量后,您永远不应该访问它。事实上,如果变量没有立即超出范围,最好在释放变量后立即将它们设置为nil。有些人只在发布模式下这样做,因此创建一个宏,如:

      #ifdef DEBUG
      #define RELEASE(x) [x release];
      #else
      #define RELEASE(x) [x release]; x = nil;
      #endif
      

      这样做的原因是为了帮助在调试模式下捕获错误(通过崩溃而不是静默 nil 指针),同时在发布模式下更安全。

      但无论如何,你不应该在释放变量后访问它。

      【讨论】:

        【解决方案3】:
        RootViewController *rootViewController = [[RootViewController alloc] initWithStyle:UITableViewStylePlain];
        

        (objectA创建,retain count为1,rootViewController指向它)

        UINavigationController *aNavigationController = [[UINavigationController alloc] initWithRootViewController:rootViewController];
        

        (objectB创建,retain count为1,aNavigationController指向它) (objectA的retain count现在是2,rootViewController和self.aNavigationController中的一些属性都指向它)

        self.navigationController = aNavigationController;
        

        (objectB的retain count现在是2,aNavigationController和self.navigationController都指向它;假设self.navigationController是一个retain属性)

        [aNavigationController release];
        

        (objectB的retain count现在是1,但是aNavigationController和self.navigationController都指向它)

        [rootViewController release];
        

        (objectA的retain count现在是1,但是rootViewController和self.aNavigationController中的一些属性都指向它)

        [rootViewController setRegions:[Region knownRegions]];
        

        (使用rootViewController访问objectA) (这样不好)

        以下是我推荐的方式:

        RootViewController *rootViewController = [[[RootViewController alloc] initWithStyle:UITableViewStylePlain] autorelease];
        [rootViewController setRegions:[Region knownRegions]];
        
        UINavigationController *aNavigationController = [[[UINavigationController alloc] initWithRootViewController:rootViewController] autorelease];
        self.navigationController = aNavigationController;
        

        【讨论】:

          猜你喜欢
          • 2014-07-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-06-26
          • 1970-01-01
          相关资源
          最近更新 更多