2015-10-21 4 views
5

निम्न उदाहरण में, मैं एक UIViewController एक UIStackViewController अपने बच्चे के रूप में है कि पेश कर रहा हूँ:क्या UISplitViewController के पास आईओएस 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 और 9.1 में, ऊपर कोड the split view controller has leaked प्रिंट होगा, यह दर्शाता है कि UIStackViewController लीक किया गया है (और अधिक महत्वपूर्ण बात, यह अपने मास्टर और विस्तार दृश्य नियंत्रकों को भी रिसाव करता है)।

+0

क्या स्प्लिटव्यू कंट्रोलर को खारिज करने से पहले बच्चे को हटा देना रिसाव को ठीक करता है? – yuf

उत्तर

4

हां, ऐप्पल स्टाफ द्वारा आईओएस 9 में मौजूद होने के लिए एक बरकरार चक्र बग confirmed रहा है।

मैंने परीक्षण किया है कि रखरखाव चक्र आईओएस 8.4 में मौजूद नहीं है, लेकिन आईओएस 9.0 और 9.1 में मौजूद है। रिसाव आईओएस 9.2 के रूप में तय किया गया है (आईओएस 9.2 सिम्युलेटर पर एक्सकोड 7.2 बीटा 2 में परीक्षण किया गया) मैंने आसानी से यह पुष्टि करने के लिए sample project रखा है कि UISplitViewController खुद को रिसाव करने का कारण बनता है (बस इसे चलाएं और जांचें कंसोल आउटपुट)।

यह मास्टर और विस्तार नियंत्रण नियंत्रकों को हटाने की अनुमति देने का प्रयास भी करता है। जैसा कि कोई देख सकता है, UISplitViewController.viewControllers सरणी संपत्ति से हटा दिए जाने के बाद भी मास्टर व्यू कंट्रोलर 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"); 
       } 
      }); 
     }); 
    }); 
} 

अद्यतन:

यहाँ नमूना परियोजना से कोड है रिसाव आईओएस 9.2 के रूप में (Xcode में आईओएस 9.2 सिम्युलेटर पर 7.2 बीटा 2 का परीक्षण) तय किया जा रहा है

+0

दिलचस्प है कि आपने आईओएस 9.4 पर इसका परीक्षण कैसे किया जब 9.1 आज बाहर आया ... Typo? : पी – erdekhayser

0

जैसा कि मुझे पता है -[UIViewController addChildViewController:] में 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 के बजाय स्टोरीबोर्ड के कंटेनर व्यू का एक संभावित कामकाज का उपयोग संभव है। मुझे पुष्टि है कि कंटेनर व्यू के बाल व्यू कंट्रोलर को ठीक से रिलीज़ किया जाएगा।

removeChildViewController:-(void)viewDidDisappear:(BOOL)animated में एक और कामकाज removeChildViewController: है। हालांकि, सेब के कर्मचारियों 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]; 
    } 
} 
संबंधित मुद्दे