Sì, un bug del ciclo di mantenimento è stato confirmed esistente in iOS 9 dallo staff Apple.
Ho verificato che il ciclo di conservazione non esiste in iOS 8.4, ma esiste in iOS 9.0 e 9.1. La perdita sembra essere corretta a partire da iOS 9.2 (testata in Xcode 7.2 beta 2 su iOS 9.2 Simulator) Ho messo insieme uno sample project per confermare facilmente se UISplitViewController si fa perdere (basta eseguirlo e controllare il uscita console).
Questo verifica anche un tentativo di consentire la deallocazione dei controller di vista principale e di dettaglio. Come si può vedere, il controller della vista master sembra ancora essere mantenuto dal UISplitViewController
anche dopo che è stato rimosso dalla proprietà dell'array UISplitViewController.viewControllers
.
Ecco il codice dal progetto di esempio:
- (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: La perdita sembra essere fissato come di iOS 9.2 (testato in Xcode 7.2 beta 2 sul iOS 9.2 Simulator)
La rimozione del bambino prima di chiudere lo splitviewcontroller risolve la perdita? – yuf