ViewDidAppear không được gọi khi mở ứng dụng từ nền


175

Tôi có Bộ điều khiển xem trong đó giá trị của tôi là 0 (nhãn) và khi tôi mở Bộ điều khiển xem đó từ một bộ điều khiển khác, ViewControllertôi đã đặt viewDidAppearthành giá trị 20 trên nhãn. Nó hoạt động tốt nhưng khi tôi đóng ứng dụng của tôi và hơn nữa tôi mở ứng dụng của tôi, nhưng giá trị không thay đổi bởi vì viewDidLoad, viewDidAppearviewWillAppearkhông có gì được gọi. Làm thế nào tôi có thể gọi khi tôi mở ứng dụng của mình. Tôi có phải làm bất cứ điều gì từ applicationDidBecomeActive?


Bạn có thể đăng thông báo cục bộ khi ứng dụng hoạt động và thêm trình điều khiển xem của bạn làm người quan sát và cập nhật giá trị.
Adil Soomro

Câu trả lời:


314

Tò mò về chuỗi sự kiện chính xác, tôi đã viết một ứng dụng như sau: (@Zohaib, bạn có thể sử dụng mã NSNotificationCenter bên dưới để trả lời câu hỏi của bạn).

// AppDelegate.m

- (void)applicationWillEnterForeground:(UIApplication *)application
{
    NSLog(@"app will enter foreground");
}

- (void)applicationDidBecomeActive:(UIApplication *)application
{
    NSLog(@"app did become active");
}

// ViewController.m

- (void)viewDidLoad
{
    [super viewDidLoad];
    NSLog(@"view did load");

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appDidBecomeActive:) name:UIApplicationDidBecomeActiveNotification object:nil];
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appWillEnterForeground:) name:UIApplicationWillEnterForegroundNotification object:nil];
}

- (void)appDidBecomeActive:(NSNotification *)notification {
    NSLog(@"did become active notification");
}

- (void)appWillEnterForeground:(NSNotification *)notification {
    NSLog(@"will enter foreground notification");
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    NSLog(@"view will appear");
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    NSLog(@"view did appear");
}

Khi khởi chạy, đầu ra trông như thế này:

2013-04-07 09:31:06.505 myapp[15459:11303] view did load
2013-04-07 09:31:06.507 myapp[15459:11303] view will appear
2013-04-07 09:31:06.511 myapp[15459:11303] app did become active
2013-04-07 09:31:06.512 myapp[15459:11303] did become active notification
2013-04-07 09:31:06.517 myapp[15459:11303] view did appear

Nhập nền sau đó nhập lại tiền cảnh:

2013-04-07 09:32:05.923 myapp[15459:11303] app will enter foreground
2013-04-07 09:32:05.924 myapp[15459:11303] will enter foreground notification
2013-04-07 09:32:05.925 myapp[15459:11303] app did become active
2013-04-07 09:32:05.926 myapp[15459:11303] did become active notification

1
Danh, bạn đã ánh xạ UIApplicationWill EntryForegroundNotification thành appDid EntryForeground :. Đó không phải là một chút sai lệch? Thông báo "sẽ" và "đã làm". Đó có phải là cố ý?
Lubiluk

@Lubiluk - không cố ý. Tôi sẽ chỉnh sửa. Nắm bắt tốt.
danh

4
Đây là một câu trả lời rất hữu ích. Tôi đã tạo một phiên bản Swift của nó ở đây .
Suragch

Trình diễn hoàn hảo chế độ nền!
Marcelo dos Santos

Chuỗi sự kiện khi bạn nhấn đúp vào nút home và đóng ứng dụng là gì?
Amjad Husseini

134

Sử dụng Mục tiêu-C

Bạn nên đăng ký một UIApplicationWillEnterForegroundNotificationtrong của bạn ViewController's viewDidLoadphương pháp và bất cứ khi nào ứng dụng trở lại từ nền bạn có thể làm bất cứ điều gì bạn muốn làm trong phương pháp đăng ký thông báo. ViewController's viewWillAppear hoặc viewDidAppear sẽ không được gọi khi ứng dụng trở lại từ nền cho tiền cảnh.

-(void)viewDidLoad{

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(doYourStuff)

  name:UIApplicationWillEnterForegroundNotification object:nil];
}

-(void)doYourStuff{

   // do whatever you want to do when app comes back from background.
}

Đừng quên hủy đăng ký thông báo mà bạn đã đăng ký.

-(void)dealloc {
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

Lưu ý nếu bạn đăng ký của bạn viewControllerđể UIApplicationDidBecomeActiveNotificationsau đó phương pháp của bạn sẽ được gọi mỗi khi ứng dụng của bạn trở nên linh hoạt, Nó không được khuyến khích đăng ký viewControllercho thông báo này.

Sử dụng Swift

Để thêm người quan sát, bạn có thể sử dụng đoạn mã sau

 override func viewDidLoad() {
    super.viewDidLoad()

     NotificationCenter.default.addObserver(self, selector: "doYourStuff", name: UIApplication.willEnterForegroundNotification, object: nil)
 }

 func doYourStuff(){
     // your code
 }

Để loại bỏ người quan sát, bạn có thể sử dụng chức năng deinit của swift.

deinit {
    NotificationCenter.default.removeObserver(self)
}

4
Đúng vậy :) đôi khi rất khó để tìm câu trả lời :)
nsgulliver

@nsgulliver Tôi có phải gọi thủ công hủy đăng ký thông báo - (void) dealloc {[[NSNotificationCenter defaultCenter] removeObserver: self]; }. Ứng dụng sẽ làm điều đó cho tôi?
ios

43

Phiên bản Swift 3.0 ++

Trong của bạn viewDidLoad, đăng ký tại trung tâm thông báo để nghe điều này được mở từ hành động nền

NotificationCenter.default.addObserver(self, selector:#selector(doSomething), name: NSNotification.Name.UIApplicationWillEnterForeground, object: nil)
        

Sau đó thêm chức năng này và thực hiện hành động cần thiết

func doSomething(){
    //...
}

Cuối cùng, thêm chức năng này để dọn sạch trình quan sát thông báo khi trình điều khiển xem của bạn bị hủy.

deinit {
    NotificationCenter.default.removeObserver(self)
}

Giải pháp dễ dàng và đơn giản để xử lý thông báo bên trong VC +1
Mo Zaatar

Không thể tin được câu trả lời hay này bị bỏ lỡ trong rất nhiều câu hỏi SO tương tự / trùng lặp khác.
Hugo Allexis Cardona

11

Swift 4.2. phiên bản

Đăng ký với NotificationCenter viewDidLoadđể được thông báo khi ứng dụng trở về từ nền

NotificationCenter.default.addObserver(self, selector: #selector(doSomething), name: UIApplication.willEnterForegroundNotification, object: nil)

Thực hiện phương pháp nên được gọi.

@objc private func doSomething() {
    // Do whatever you want, for example update your view.
}

Bạn có thể loại bỏ người quan sát một khi ViewControllerbị phá hủy. Điều này chỉ được yêu cầu bên dưới iOS9 và macOS 10.11

deinit {
    NotificationCenter.default.removeObserver(self)
}

1
FYI Tôi chắc chắn rằng bạn không cần phải bận tâm đến việc loại bỏ các nhà quan sát nữa trong những ngày này ...
Fattie

3

Chỉ cần có bộ điều khiển xem của bạn đăng ký UIApplicationWillEnterForegroundNotificationthông báo và phản ứng phù hợp.


Làm thế nào tôi sẽ làm điều đó? tôi đã gọi viewContoder của mình trong applicationDidBecomeActive nhưng. nó chồng lên viewContoder hay nó ổn để làm điều đó?
Zohaib

2
Đừng gọi viewControll của bạn trong applicationDidBecomeActive (dù sao cũng sai vì nó được gọi nhiều lần). Đăng ký thông báo trong viewDidLoadlike @nsgulliver của bạn được đề xuất. Bạn viewDidAppearcũng sẽ gọi doYourStuffđể đặt nhãn của bạn với giá trị mong muốn.
andreagiavatto

3

Tôi nghĩ rằng việc đăng ký UIApplicationWill EntryForegroundNotification là rủi ro vì bạn có thể kết thúc với nhiều hơn một bộ điều khiển phản ứng với thông báo đó. Không có gì đảm bảo rằng các bộ điều khiển này vẫn hiển thị khi nhận được thông báo.

Dưới đây là những gì tôi làm: Tôi buộc gọi viewDidAppear trên bộ điều khiển hoạt động trực tiếp từ phương thức didBecomeActive của ứng dụng:

Thêm mã dưới đây để - (void)applicationDidBecomeActive:(UIApplication *)application

UIViewController *activeController = window.rootViewController;
if ([activeController isKindOfClass:[UINavigationController class]]) {
    activeController = [(UINavigationController*)window.rootViewController topViewController];
}
[activeController viewDidAppear:NO];

7
Nó được đảm bảo nếu bộ điều khiển hủy đăng ký (nếu cần) cho UIApplicationWill EntryForegroundNotification trong viewWillDisappear thay vì trong dealloc. Gọi viewDidAppear rõ ràng trông giống như một bản hack đối với tôi, nó phá vỡ ngữ nghĩa (quan điểm cá nhân) và có thể khiến mọi người nhầm lẫn (từ kinh nghiệm).
joakim

3

hãy thử thêm phần này vào ứng dụng AppDelegateWill EntryForeground.

func applicationWillEnterForeground(_ application: UIApplication) {        
    // makes viewWillAppear run
    self.window?.rootViewController?.beginAppearanceTransition(true, animated: false)
    self.window?.rootViewController?.endAppearanceTransition()
}

2

Theo tài liệu của Apple:

(void)beginAppearanceTransition:(BOOL)isAppearing animated:(BOOL)animated;

Mô tả:
Nói với một bộ điều khiển con sự xuất hiện của nó sắp thay đổi. Nếu bạn đang thực hiện một bộ điều khiển bộ chứa tùy chỉnh, hãy sử dụng phương pháp này để nói với trẻ rằng các khung nhìn của nó sắp xuất hiện hoặc biến mất . Đừng gọi viewWillAppear:, viewWillDisappear:, viewDidAppear:, hoặc viewDidDisappear:trực tiếp .

(void)endAppearanceTransition;

Sự miêu tả:

Nói với một bộ điều khiển con sự xuất hiện của nó đã thay đổi. Nếu bạn đang triển khai bộ điều khiển bộ chứa tùy chỉnh, hãy sử dụng phương pháp này để nói với trẻ rằng quá trình chuyển đổi chế độ xem đã hoàn tất.

Mã mẫu:

(void)applicationDidEnterBackground:(UIApplication *)application
{

    [self.window.rootViewController beginAppearanceTransition: NO animated: NO];  // I commented this line

    [self.window.rootViewController endAppearanceTransition]; // I commented this line

}

Câu hỏi: Làm thế nào tôi sửa?

Trả lời : Tôi tìm thấy đoạn này trong ứng dụng. Dòng này làm cho ứng dụng của tôi không nhận được bất kỳ thông báo nào của ViewWillAppear. Khi tôi nhận xét những dòng này nó hoạt động tốt .

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.