Mengapa metode UIApplicationDelegate `application (_: configurationForConnecting: options:)` tidak dipanggil dengan andal

Aug 21 2020

Isu:

Saya menemukan beberapa perilaku tak terduga terkait metode AppDelegate application(_:configurationForConnecting:options:).

Dokumentasi menyatakan:

UIKit memanggil metode ini sesaat sebelum membuat adegan baru.

Saya berharap ini terjadi setiap kali aplikasi diluncurkan.
Metode ini memang dipanggil saat saya meluncurkan aplikasi untuk pertama kalinya, namun untuk semua peluncuran berikutnya, tidak .

Reproduksi:

Saya memiliki kasus uji yang sangat sederhana untuk direproduksi:

  • Xcode 12> Buat Proyek baru> iOS> Aplikasi (UIKit / Storyboard)
  • tambahkan pernyataan debugging dalam metode AppDelegateseperti ini:
      // from Apple's sample project:
      func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
          // Called when a new scene session is being created.
          // Use this method to select a configuration to create the new scene with.
          print("I was called!").  // <--- debugging statement
          return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
      }
    
  • jalankan aplikasi> "Saya dipanggil!" dicetak di konsol
  • jalankan aplikasi lagi> tidak ada yang dicetak.

Pertanyaan:

Mengapa application(_:configurationForConnecting:options:)tidak dipanggil pada peluncuran kedua?
(Apakah ini perilaku yang diharapkan, jika ya mengapa / Apakah itu bug oleh Apple)

Jawaban

3 Adrian Oct 21 2020 at 05:10

Ini tampaknya merupakan perilaku yang diharapkan, dan masuk akal setelah Anda memahami apa yang sedang terjadi, tetapi tidak didokumentasikan. Saya baru saja menghabiskan waktu yang cukup traumatis untuk mengungkapnya. Oh, Apple.

Hal utama yang perlu diketahui adalah saat Anda meluncurkan kembali aplikasi, jendela dari proses sebelumnya akan dipulihkan.

(Ini juga membantu untuk mengingat bahwa aplikasi dapat memiliki beberapa jenis jendela - masing-masing diwakili oleh konfigurasi adegan - itulah sebabnya Anda mungkin menerapkan metode delegasi ini di tempat pertama.)

Kasus 1: Aplikasi diluncurkan untuk pertama kalinya

Aplikasi tidak tahu jenis adegan apa yang harus diletakkan di jendela, dan panggilan application(_:configurationForConnecting:options:)untuk mengetahuinya. Sejauh ini semuanya seperti yang kita harapkan. (Jika Anda tidak menerapkan metode delegasi ini, itu hanya akan kembali ke entri pertama yang sesuai dalam Info.plistmanifes adegan Anda, jika ada.)

Kasus 2: Jendela baru dibuat (untuk aplikasi yang mendukung banyak jendela)

(misalnya dengan menyeret ikon dok di iPad). Aplikasi juga tidak tahu apa yang harus dimasukkan ke dalam jendela ini. Sama seperti kasus 1.

Kasus 3: Aplikasi diluncurkan kembali

OS ingin memulihkan jendela Anda. Untuk melakukan ini, ia mengingat konfigurasi adegan jendela yang Anda buka terakhir kali. Mengherankan! Ia tahu adegan apa yang harus diletakkan di jendela, dan tidak meminta delegasi aplikasi Anda. Itu terus berjalan dan membuat adegan menggunakan konfigurasi yang diingat.

Untuk pengembang yang buruk yang berpikir tentang jendela yang dibuat saat aplikasi dijalankan, ini membingungkan. Tetapi jika Anda berpikir dalam istilah windows dipulihkan saat startup, tidak dibuat - bahkan ketika hanya ada satu - itu mulai masuk akal.


Sekarang, jika Anda ingin mengatur ulang sehingga jendela Anda dilupakan dan metode delegasi Anda dipanggil pada peluncuran berikutnya:

  • untuk iOS, hapus aplikasi
  • untuk Catalyst, hapus wadah aplikasi

Catatan 1: Di Catalyst, tampaknya hanya jendela pertama yang dipulihkan saat peluncuran ulang, tetapi jika tidak, perilakunya sama seperti di atas. Sekarang amati bahwa ini tidak benar. Mungkin itu tidak konsisten.

Catatan 2: Anda juga dapat memulihkan konten windows Anda , bukan hanya tipenya , menggunakan UIWindowSceneDelegatedan UISceneSession.stateRestorationActivity, tetapi itu cerita lain.