Đường thẳng này:
[self dismissViewControllerAnimated:YES completion:nil];
không phải gửi một thông điệp cho chính nó, nó thực sự đang gửi một thông điệp đến VC đang trình bày của nó, yêu cầu nó thực hiện việc loại bỏ. Khi bạn trình bày một VC, bạn tạo ra mối quan hệ giữa VC trình bày và VC được trình bày. Vì vậy, bạn không nên hủy VC đang trình bày khi nó đang trình bày (VC đã trình bày không thể gửi lại thông báo loại bỏ đó…). Vì bạn không thực sự tính đến nó, bạn đang để ứng dụng ở trạng thái bối rối. Xem câu trả lời của tôi Loại bỏ Bộ điều khiển dạng xem được trình bày
trong đó tôi đề xuất phương pháp này được viết rõ ràng hơn:
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];
Trong trường hợp của bạn, bạn cần đảm bảo rằng tất cả các kiểm soát được thực hiện trong mainVC
. Bạn nên sử dụng một đại biểu để gửi thông báo chính xác trở lại MainViewController từ ViewController1, để mainVC có thể loại bỏ VC1 và sau đó trình bày VC2.
Trong VC2 VC1, hãy thêm một giao thức trong tệp .h của bạn phía trên @interface:
@protocol ViewController1Protocol <NSObject>
- (void)dismissAndPresentVC2;
@end
và hạ xuống trong cùng một tệp trong phần @interface, khai báo một thuộc tính để giữ con trỏ đại biểu:
@property (nonatomic,weak) id <ViewController1Protocol> delegate;
Trong tệp VC1 .m, phương thức nút loại bỏ sẽ gọi phương thức ủy quyền
- (IBAction)buttonPressedFromVC1:(UIButton *)sender {
[self.delegate dissmissAndPresentVC2]
}
Bây giờ trong mainVC, hãy đặt nó làm đại biểu của VC1 khi tạo VC1:
- (IBAction)present1:(id)sender {
ViewController1* vc = [[ViewController1 alloc] initWithNibName:@"ViewController1" bundle:nil];
vc.delegate = self;
[self present:vc];
}
và thực hiện phương pháp ủy quyền:
- (void)dismissAndPresent2 {
[self dismissViewControllerAnimated:NO completion:^{
[self present2:nil];
}];
}
present2:
có thể là phương pháp giống như phương pháp VC2Pressed:
IBAction nút của bạn . Lưu ý rằng nó được gọi từ khối hoàn thành để đảm bảo rằng VC2 không được hiển thị cho đến khi VC1 bị loại bỏ hoàn toàn.
Bây giờ bạn đang di chuyển từ VC1-> VCMain-> VC2, vì vậy bạn có thể chỉ muốn một trong các chuyển đổi được làm động.
cập nhật
Trong nhận xét của mình, bạn bày tỏ sự ngạc nhiên về sự phức tạp cần thiết để đạt được một điều tưởng chừng như đơn giản. Tôi đảm bảo với bạn, mô hình ủy quyền này rất trung tâm đối với phần lớn Objective-C và Cocoa, và ví dụ này là về điều đơn giản nhất bạn có thể nhận được, mà bạn thực sự nên cố gắng để làm cho thoải mái với nó.
Trong Hướng dẫn lập trình bộ điều khiển chế độ xem của Apple, họ có điều này để nói :
Loại bỏ bộ điều khiển dạng xem được trình bày
Khi đến lúc loại bỏ bộ điều khiển dạng xem đã trình bày, phương pháp ưu tiên là để bộ điều khiển dạng xem trình bày loại bỏ nó. Nói cách khác, bất cứ khi nào có thể, bộ điều khiển chế độ xem tương tự đã trình bày bộ điều khiển chế độ xem cũng phải chịu trách nhiệm loại bỏ nó. Mặc dù có một số kỹ thuật để thông báo cho bộ điều khiển chế độ xem trình bày rằng bộ điều khiển chế độ xem đã trình bày của nó nên bị loại bỏ, kỹ thuật được ưu tiên là ủy quyền. Để biết thêm thông tin, hãy xem “Sử dụng ủy quyền để giao tiếp với những người kiểm soát khác”.
Nếu bạn thực sự suy nghĩ kỹ về những gì bạn muốn đạt được và cách bạn thực hiện nó, bạn sẽ nhận ra rằng việc nhắn tin cho MainViewController của bạn để thực hiện tất cả công việc là cách giải quyết hợp lý duy nhất khiến bạn không muốn sử dụng NavigationController. Nếu bạn làm sử dụng một NavController, có hiệu lực bạn là 'ủy thác', thậm chí nếu không muốn nói một cách rõ ràng, để các navController để làm tất cả công việc. Cần có một số đối tượng theo dõi trung tâm những gì đang diễn ra với điều hướng VC của bạn và bạn cần một số phương pháp giao tiếp với nó, bất cứ điều gì bạn làm.
Trên thực tế, lời khuyên của Apple hơi cực đoan ... trong những trường hợp bình thường, bạn không cần phải đưa ra một phương pháp và người ủy quyền chuyên dụng, bạn có thể dựa vào [self presentingViewController] dismissViewControllerAnimated:
- đó là khi trong những trường hợp như của bạn, bạn muốn việc sa thải của mình có những tác động khác trên điều khiển từ xa đối tượng mà bạn cần phải chăm sóc.
Đây là một cái gì đó bạn có thể tưởng tượng để làm việc mà không có tất cả các rắc rối của đại biểu ...
- (IBAction)dismiss:(id)sender {
[[self presentingViewController] dismissViewControllerAnimated:YES
completion:^{
[self.presentingViewController performSelector:@selector(presentVC2:)
withObject:nil];
}];
}
Sau khi yêu cầu trình điều khiển trình bày loại bỏ chúng tôi, chúng tôi có một khối hoàn thành gọi một phương thức trong PresentationViewController để gọi VC2. Không cần đại biểu. (Một điểm hấp dẫn lớn của các khối là họ giảm nhu cầu về các đại biểu trong những trường hợp này). Tuy nhiên, trong trường hợp này, có một số điều cản trở ...
- trong VC1, bạn không biết rằng mainVC thực hiện phương thức
present2
- bạn có thể gặp phải các lỗi hoặc sự cố khó gỡ lỗi. Đại biểu giúp bạn để tránh điều này.
- một khi VC1 bị loại bỏ, nó không thực sự xung quanh để thực thi khối hoàn thành ... hay là? Self.presentingViewController có nghĩa là gì nữa không? Bạn không biết (tôi cũng vậy) ... với một đại biểu, bạn không có sự không chắc chắn này.
- Khi tôi cố gắng chạy phương pháp này, nó chỉ bị treo mà không có cảnh báo hoặc lỗi.
Vì vậy, xin vui lòng ... dành thời gian để tìm hiểu đoàn!
update2
Trong nhận xét của bạn, bạn đã quản lý để làm cho nó hoạt động bằng cách sử dụng điều này trong trình xử lý nút loại bỏ của VC2:
[self.view.window.rootViewController dismissViewControllerAnimated:YES completion:nil];
Điều này chắc chắn đơn giản hơn nhiều, nhưng nó để lại cho bạn một số vấn đề.
Khớp nối chặt chẽ
Bạn đang kết nối cấu trúc viewController với nhau. Ví dụ: nếu bạn chèn một viewController mới trước mainVC, hành vi bắt buộc của bạn sẽ bị hỏng (bạn sẽ điều hướng đến hành vi trước đó). Trong VC1, bạn cũng phải # nhập VC2. Do đó, bạn có khá nhiều phụ thuộc lẫn nhau, điều này phá vỡ các mục tiêu OOP / MVC.
Khi sử dụng các đại biểu, cả VC1 và VC2 đều không cần biết bất kỳ điều gì về mainVC hoặc các tiền thân của nó, vì vậy chúng tôi giữ mọi thứ được kết hợp lỏng lẻo và mô-đun.
Bộ nhớ
VC1 vẫn chưa biến mất, bạn vẫn giữ hai con trỏ tới nó:
presentedViewController
tài sản của mainVC
presentingViewController
Tài sản của VC2
Bạn có thể kiểm tra điều này bằng cách ghi nhật ký và cũng chỉ bằng cách thực hiện điều này từ VC2
[self dismissViewControllerAnimated:YES completion:nil];
Nó vẫn hoạt động, vẫn đưa bạn trở lại VC1.
Điều đó đối với tôi dường như là một sự rò rỉ ký ức.
Manh mối cho điều này nằm trong cảnh báo bạn đang nhận được ở đây:
[self presentViewController:vc2 animated:YES completion:nil];
[self dismissViewControllerAnimated:YES completion:nil];
Logic bị phá vỡ, vì bạn đang cố gắng loại bỏ VC trình bày trong đó VC2 là VC trình bày. Thông báo thứ hai không thực sự được thực thi - có lẽ một số điều xảy ra, nhưng bạn vẫn còn lại hai con trỏ đến một đối tượng mà bạn nghĩ rằng bạn đã loại bỏ. ( chỉnh sửa - Tôi đã kiểm tra điều này và nó không quá tệ, cả hai đối tượng đều biến mất khi bạn quay lại mainVC )
Đó là một cách nói khá dài dòng - làm ơn, hãy sử dụng các đại biểu. Nếu nó hữu ích, tôi đã thực hiện một mô tả ngắn gọn khác về mẫu ở đây: Việc
chuyển một bộ điều khiển trong một trình tạo có luôn là một phương pháp không tốt không?
cập nhật 3
Nếu bạn thực sự muốn tránh người được ủy quyền, đây có thể là cách tốt nhất:
Trong VC1:
[self presentViewController:VC2
animated:YES
completion:nil];
Nhưng đừng bác bỏ bất cứ điều gì ... như chúng tôi đã xác định, nó không thực sự xảy ra.
Trong VC2:
[self.presentingViewController.presentingViewController
dismissViewControllerAnimated:YES
completion:nil];
Như chúng tôi (biết) chúng tôi chưa loại bỏ VC1, chúng tôi có thể liên hệ lại thông qua VC1 đến MainVC. MainVC loại bỏ VC1. Bởi vì VC1 đã biến mất, VC2 được trình bày đi cùng với nó, vì vậy bạn quay lại MainVC trong trạng thái sạch sẽ.
Nó vẫn được kết hợp chặt chẽ, vì VC1 cần biết về VC2 và VC2 cần biết rằng nó đã được đến qua MainVC-> VC1, nhưng đó là điều tốt nhất bạn sẽ nhận được mà không cần một chút ủy quyền rõ ràng.