2015-10-21 12 views
5

が、私はその子としてUIStackViewControllerを持ってUIViewControllerを提示しています:UISplitViewControllerにはiOS 9の保持サイクルのバグはありますか?次の例では

iOSの9で
UIViewController *splitViewParentVC = UIViewController.new; 

UIViewController *masterVC = UIViewController.new; 
UIViewController *detailVC = UIViewController.new; 

UISplitViewController *splitViewController = [[UISplitViewController alloc] init]; 
splitViewController.viewControllers = @[masterVC, detailVC]; 

[splitViewParentVC addChildViewController:splitViewController]; 
[splitViewParentVC.view addSubview:splitViewController.view]; 
[splitViewController didMoveToParentViewController:splitViewParentVC]; 
splitViewController.view.frame = splitViewParentVC.view.bounds; 
splitViewController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 

__weak UISplitViewController *wSplitViewController = splitViewController; 

[self presentViewController:splitViewParentVC animated:YES completion:nil]; 

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
    [self dismissViewControllerAnimated:YES completion:^{ 
     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
      if (wSplitViewController) { 
       NSLog(@"the split view controller has leaked"); 
      } else { 
       NSLog(@"the split view controller didn't leak"); 
      } 
     }); 
    }]; 
}); 

と9.1、上記のコードはUIStackViewControllerが(もっと重要なのは漏洩したことを示す、the split view controller has leakedが印刷されます、マスタービューと詳細ビューコントローラもリークします)。

+0

splitviewcontrollerを終了する前に子供を削除すると、リークが修正されますか? – yuf

答えて

4

はい、Appleスタッフによって保持期間のバグがconfirmedがiOS 9に存在しています。

私は、保持サイクルがiOS 8.4では存在しないが、iOS 9.0および9.1では存在することをテストしました。 漏れは、私は簡単にUISplitViewControllerは(それを実行し、チェック漏れて自分自身を起こしたか否かを確認するために一緒にsample projectを入れている(iOSの9.2シミュレータ上でのXcode 7.2のベータ2でテスト)のiOS 9.2のように固定しているようですコンソール出力)。

これは、マスタービュービューコントローラと詳細ビューコントローラの割り当てを解除する試みもテストします。ご覧のように、配列プロパティから削除された後でも、マスタービューコントローラはUISplitViewControllerによって保持されているように見えます。

- (void)viewDidLoad { 
    [super viewDidLoad]; 

    [self testSplitViewControllerRetainCycleWithCompletion:^{ 
     [self testManuallyFreeingUpMasterAndDetailViewControllers]; 
    }]; 
} 

- (void)testSplitViewControllerRetainCycleWithCompletion:(void (^)())completion { 

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 

     UIViewController *splitViewParentVC = UIViewController.new; 

     UIViewController *masterVC = UIViewController.new; 
     UIViewController *detailVC = UIViewController.new; 

     UISplitViewController *splitViewController = [[UISplitViewController alloc] init]; 
     splitViewController.viewControllers = @[masterVC, detailVC]; 
     splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible; 
     splitViewController.preferredPrimaryColumnWidthFraction = 0.3125; // 320/1024 
     splitViewController.minimumPrimaryColumnWidth = 100; 

     [splitViewParentVC addChildViewController:splitViewController]; 
     [splitViewParentVC.view addSubview:splitViewController.view]; 
     [splitViewController didMoveToParentViewController:splitViewParentVC]; 
     splitViewController.view.frame = splitViewParentVC.view.bounds; 
     splitViewController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 

     __weak UISplitViewController *wSplitViewController = splitViewController; 
     __weak UIViewController *wMaster = masterVC; 
     __weak UIViewController *wDetail = detailVC; 

     [self presentViewController:splitViewParentVC animated:YES completion:nil]; 

     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
      [self dismissViewControllerAnimated:YES completion:^{ 
       dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
        if (wSplitViewController) { 
         NSLog(@"the split view controller has leaked"); 
        } else { 
         NSLog(@"the split view controller didn't leak"); 
        } 
        if (wMaster) { 
         NSLog(@"the master view controller has leaked"); 
        } else { 
         NSLog(@"the master view controller didn't leak"); 
        } 
        if (wDetail) { 
         NSLog(@"the detail view controller has leaked"); 
        } else { 
         NSLog(@"the detail view controller didn't leak"); 
        } 

        completion(); 
       }); 
      }]; 
     }); 
    }); 
} 

- (void)testManuallyFreeingUpMasterAndDetailViewControllers { 

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 

     UIViewController *splitViewParentVC = UIViewController.new; 

     UIViewController *masterVC = UIViewController.new; 
     UIViewController *detailVC = UIViewController.new; 

     UISplitViewController *splitViewController = [[UISplitViewController alloc] init]; 
     splitViewController.viewControllers = @[masterVC, detailVC]; 
     splitViewController.preferredDisplayMode = UISplitViewControllerDisplayModeAllVisible; 
     splitViewController.preferredPrimaryColumnWidthFraction = 0.3125; // 320/1024 
     splitViewController.minimumPrimaryColumnWidth = 100; 

     [splitViewParentVC addChildViewController:splitViewController]; 
     [splitViewParentVC.view addSubview:splitViewController.view]; 
     [splitViewController didMoveToParentViewController:splitViewParentVC]; 
     splitViewController.view.frame = splitViewParentVC.view.bounds; 
     splitViewController.view.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth; 

     __weak UIViewController *wMaster = masterVC; 
     __weak UIViewController *wDetail = detailVC; 

     [self presentViewController:splitViewParentVC animated:YES completion:nil]; 

     dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
      [self dismissViewControllerAnimated:YES completion:nil]; 

      splitViewController.viewControllers = @[UIViewController.new, UIViewController.new]; 

      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 
       if (wMaster) { 
        NSLog(@"the master view controller has STILL leaked even after an attempt to free it"); 
       } else { 
        NSLog(@"the master view controller didn't leak"); 
       } 
       if (wDetail) { 
        NSLog(@"the detail view controller has STILL leaked even after an attempt to free it"); 
       } else { 
        NSLog(@"the detail view controller didn't leak"); 
       } 
      }); 
     }); 
    }); 
} 

をUPDATE:リークがIOSの9.2のように固定されているように見える(IOSの9.2シミュレータ上でのXcode 7.2ベータ2で試験)

+0

9.1が今日出てきたときにiOS 9.4でどのようにテストしたのか興味深いです... Typo? :P – erdekhayser

0
ここ

はサンプルプロジェクトからのコードであります

がメモリリークの問題を抱えていることはiOS 9.0~9.1です。だから私はUISplitViewControllerの障害ではないと思う。 Snipets次のように、

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    MyFirstViewController *vc = [self.storyboard instantiateViewControllerWithIdentifier:@"MyFirstViewController"]; 
    [self addChildViewController:vc]; 
    [self.view addSubview:vc.view]; 
    [vc didMoveToParentViewController:self]; 
} 

あなたは現在のビューコントローラから退避場合MyFirstViewControllerさんにdeallocが呼び出されていないことがわかります。

考えられる回避策は、コード内にaddChildViewControllerの代わりにコンテナビューコンテナビューを使用してください。私はコンテナビューの子ビューコントローラが適切にリリースされることを確信しています。

別の回避策は、-(void)viewDidDisappear:(BOOL)animatedremoveChildViewController:です。ただし、Appleのスタッフmentionedとして、この回避策はお勧めしません。

- (void)viewDidDisappear:(BOOL)animated { 
    [super viewDidDisappear:animated]; 
    NSArray<__kindof UIViewController *> * children = self.childViewControllers; 
    for (UIViewController *vc in children) { // not recommended 
     [vc willMoveToParentViewController:nil]; 
     [vc.view removeFromSuperview]; 
     [vc removeFromParentViewController]; 
    } 
} 
関連する問題