2012-12-12 72 views
14

我有一個自定義容器UIViewController有六個子UIViewControllers和一組用戶交互切換子視圖控制器的選項卡。問題是當我的容器視圖控制器被釋放時,子視圖控制器不是。容器UIViewController不釋放它的子視圖控制器

我已驗證子視圖控制器不會通過向其dealloc方法添加一些調試代碼來釋放子視圖控制器,只要它們的視圖未添加到容器視圖控制器視圖中,它們就會被釋放。

下面是我用來創建自定義容器視圖控制器的代碼摘錄。 viewController指針是iVars。我也使用ARC,所以這就是爲什麼沒有實際的發佈呼叫。

- (void)init 
{ 
    if ((self = [super init])) { 
     vc1 = [[UIViewController alloc] init]; 
     [self addChildViewController:vc1]; 

     vc2 = [[UIViewController alloc] init]; 
     [self addChildViewController:vc2]; 

     vc3 = [[UIViewController alloc] init]; 
     [self addChildViewController:vc3]; 

     vc4 = [[UIViewController alloc] init]; 
     [self addChildViewController:vc4]; 

     vc5 = [[UIViewController alloc] init]; 
     [self addChildViewController:vc5]; 

     vc6 = [[UIViewController alloc] init]; 
     [self addChildViewController:vc6]; 
    } 
    return self; 
} 

- (void)dealloc 
{ 
    [vc1 removeFromParentViewController]; 
    vc1 = nil; 

    [vc2 removeFromParentViewController]; 
    vc2 = nil; 

    [vc3 removeFromParentViewController]; 
    vc3 = nil; 

    [vc4 removeFromParentViewController]; 
    vc4 = nil; 

    [vc5 removeFromParentViewController]; 
    vc5 = nil; 

    [vc6 removeFromParentViewController]; 
    vc6 = nil; 
} 

- (void)switchFromViewController:(UIViewController *)fromViewController toViewController:(UIViewController *)toViewController 
{ 
    if (fromViewController) { 
     [fromViewController.view removeFromSuperview]; 
    } 

    [self.view addSubview:toViewController]; 
    toViewController.view.frame = self.view.bounds; 
} 

你們都有什麼想法我做錯了嗎?

+0

出於好奇,您會引用控制顯示哪個孩子的選項卡。你是如何實現它的?我問,因爲我看到你有孩子的'frame'被設置爲'self.view.frame',所以我不明白父母的視圖上你會顯示這個標籤控件的位置。 – Rob

+0

這只是我的實際代碼正在做的一個超級快速示例,所以它不是100%的想法。在我的實際應用程序中,有一些標籤沿垂直方向運行,然後在主視圖控制器中有一個視圖將子視圖控制器視圖放入其中,然後將其框架設置爲childViewController.frame = contentContainerView.bounds; –

+0

這很有道理。乍看起來,看着它整個屏幕上的遏制的例子,讓我懷疑是否需要收容。聽起來像你有一個很好的計劃,但。抱歉抱怨你。 ;) – Rob

回答

11

正如我懷疑,這個問題是不相關的方式方法問題中的視圖控制器包含代碼,而是您添加的觀察者(您在本問題的答案中討論的內容):

[[NSNotificationCenter defaultCenter] addObserverForName:kUpdateEventName object:nil queue:nil usingBlock:^(NSNotification *note) { 
    // do stuff when update happen 
}]; 

而且你想與

[[NSNotificationCenter defaultCenter] removeObserver:self name:kUpdateEventName object:nil]; 

因此將其刪除,有兩個問題:

  1. 如果使用addObserverForName:object:queue:,這是不是刪除該觀察者的正確方法。相反,定義一個屬性,以保持觀察者的軌跡:

    @property (nonatomic, weak) id<NSObject> notification; 
    

    然後保存到觀察者的引用,當你創建:

    self.notification = [[NSNotificationCenter defaultCenter] addObserverForName:kUpdateEventName object:nil queue:nil usingBlock:^(NSNotification *note) { 
        // do something 
    }]; 
    

    而當你想刪除它,使用此引用:

    [[NSNotificationCenter defaultCenter] removeObserver:self.notification]; 
    

    這將確保觀察者將被正確地移除。

  2. 在觀察者就位時釋放子視圖控制器失敗意味着您傳遞給addObserverForName:object:queue:的此塊必須引用self。如果您試圖在dealloc中正確刪除此觀察者(如上所示),您仍然會有一個強大的參考週期(以前稱爲保留週期)。這在許多方面解決,但最強大的模式是通過使用weakSelf模式,以防止在首位有力的參考週期:

    typeof(self) __weak weakSelf = self; 
    
    self.notification = [[NSNotificationCenter defaultCenter] addObserverForName:kFooNotification object:nil queue:nil usingBlock:^(NSNotification *note) { 
        // use `weakSelf` in this block; not `self` 
    }]; 
    

我原來的答覆是下面:


雖然SRIKANTH是正確的,addChildViewController後,你應該叫didMoveToParentViewController:selfremoveFromParentViewController之前,你應該叫willMoveToParentViewController:nil。但那不是你的問題。實際上,我使用了代碼的變體(即使沒有dealloc),孩子們的控制器也可以很好地發佈。底線,我懷疑你的問題在別處,可能是一個保留週期的地方。例如,你的孩子有沒有強烈的參考父母?你使用循環定時器嗎?你引用一些標籤。你沒有使用標籤欄控制器,是嗎?這應該是這樣的。

+1

感謝信息人。是的,當你提到我發佈的原始代碼是發佈孩子時,我決定嘗試將我的子視圖控制器類切換爲一個新的子類,除非在dealloc期間註銷標題,否則它並不真正做任何事情。就像你沒有。一旦我這樣做,子視圖控制器開始正確釋放。所以我想我在其他地方有一個問題。再次感謝您的幫助! –

24

這不是添加和刪除子視圖控制器

[childViewController willMoveToParentViewController:nil]; 
    [childViewController view] removeFromSuperview]; 
    [childViewController removeFromParentViewController]; 

被刪除,並添加它

[parentViewController addChildViewController:childViewController]; 
    [parentViewController.view addSubview:childViewController.view]; 
    [childViewController didMoveToParentViewController:parentViewController]; 
+2

刪除代碼中的第二行缺少一個初始[ – crgt

2

小時後,並試圖找出最後事情我小時,如果你想看到的代碼段和小的細節上的OP的代碼示例原來答案的其餘部分請參閱修訂歷史記錄]發現是什麼導致我的子視圖控制器無法正確釋放。

每個視圖控制器都在其中聲明瞭以下通知,以便它們可以響應各種事件。

[[NSNotificationCenter defaultCenter] addObserverForName:UPDATE_EVENT object:nil queue:nil usingBlock:^(NSNotification *note) { 
    // do stuff when update happen 
}]; 

原因是某些原因導致我的視​​圖控制器無法正確釋放。我猜這是將視圖控制器添加到NSNotificationCenters觀察者列表中,並且在我執行以下命令時未被刪除。

[[NSNotificationCenter defaultCenter] removeObserver:self name:UPDATE_EVENT object:nil]; 

因此,要解決我的問題,我只是改變了通知註冊如下。

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(updateEvent:) name:UPDATE_EVENT object:nil]; 

我不知道爲什麼我註冊通知的方式是不是讓我的視圖控制器正確釋放,但是這似乎已經固定它。如果任何人有任何見解,爲什麼會發生這個問題,請讓我知道。

謝謝!

+2

我認爲附加到觀察者的「更新時發生的事情」塊將關閉對「自我」的非塊安全引用並泄漏引用。 – jdc

相關問題