簡體   English   中英

SwiftUI app生命周期iOS14 AppDelegate代碼放哪里?

[英]SwiftUI app life cycle iOS14 where to put AppDelegate code?

現在AppDelegateSceneDelegate已從 SwiftUI 中刪除,我將以前在SceneDelegateAppDelegate中的代碼 Firebase 配置放在哪里?

所以我的AppDelegate目前有這段代碼:

我現在應該把這段代碼放在哪里?

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    // Override point for customization after application launch.
    
    FirebaseConfiguration.shared.setLoggerLevel(.min)
    FirebaseApp.configure()
    return true
}

這是 SwiftUI 生命周期的解決方案。 用 Xcode 12b / iOS 14 測試

import SwiftUI
import UIKit

// no changes in your AppDelegate class
class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        print(">> your code here !!")
        return true
    }
}

@main
struct Testing_SwiftUI2App: App {

    // inject into SwiftUI life-cycle via adaptor !!!
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

在您的App中覆蓋初始化程序也可以:

import SwiftUI
import Firebase

@main
struct BookSpineApp: App {
  
  init() {
    FirebaseApp.configure()
  }
  
  var body: some Scene {
    WindowGroup {
      BooksListView()
    }
  }
}

在這里找到更詳細的文章:

您根本不應該將這種代碼放在應用程序委托中,否則您最終將面臨大規模應用程序委托 相反,您應該考慮將代碼重構為更有意義的部分,然后將正確的部分放在正確的位置。 對於這種情況,您唯一需要做的就是確保在應用程序准備就緒后代碼正在執行這些功能並且只執行一次。 所以init方法可能很棒:

@main
struct MyApp: App {
    init() {
        setupFirebase()
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

private extension MyApp {
    func setupFirebase() {
        FirebaseConfiguration.shared.setLoggerLevel(.min)
        FirebaseApp.configure()
    }
}

應用代理?

您可以擁有自己的自定義 class 並將其指定為delegate 但請注意,它不適用於分配之前發生的事件。 例如:

class CustomDelegate: NSObject, UIApplicationDelegate {
    static let Shared = CustomDelegate()
}

然后:

UIApplication.shared.delegate = CustomDelegate.Shared

觀察通知

大多數AppDelegate方法實際上是在觀察您可以手動觀察的通知,而不是定義新的 class。 例如:

NotificationCenter.default.addObserver(
    self,
    selector: #selector(<#T##@objc method#>),
    name: UIApplication.didBecomeActiveNotification,
    object: nil
)

原生AppDelegate包裝器

您可以直接將應用委托注入@main結構:

@UIApplicationDelegateAdaptor(CustomDelegate.self) var appDelegate

注意:使用AppDelegate

請記住,添加 AppDelegate 意味着您正在取消默認的多平台支持,並且您必須手動檢查平台。

您還可以將新的 ScenePhase 用於 AppDelegate 和 SceneDelegate 擁有的某些代碼。 喜歡去后台或變得活躍。

struct PodcastScene: Scene {
    @Environment(\.scenePhase) private var phase

    var body: some Scene {
        WindowGroup {
            TabView {
                LibraryView()
                DiscoverView()
                SearchView()
            }
        }
        .onChange(of: phase) { newPhase in
            switch newPhase {
            case .active:
                // App became active
            case .inactive:
                // App became inactive
            case .background:
                // App is running in the background
            @unknown default:
                // Fallback for future cases
            }
        }
    }
}

示例信用: https://wwdcbysundell.com/2020/building-entire-apps-with-swiftui/

請注意,以下方法將停止跨平台支持,因此僅應在您計划僅為 iOS 構建時使用。

在 Xcode 12-beta 中創建 SwiftUI 應用程序時,您仍然可以擁有 AppDelegate 和 SceneDelegate。

您只需要確保在創建應用程序時為生命周期選擇了正確的選項。

在此處輸入圖像描述

確保為生命周期選擇UIKit App Delegate ,您將獲得 AppDelegate 和 SceneDelegate

我還建議為此使用主Appinit方法,因為它似乎可以安全使用(有任何異議嗎?)。

我通常做的可能有用的分享是擁有幾個實用程序類型,並結合Builder模式。

/// An abstraction for a predefined set of functionality,
/// aimed to be ran once, at app startup.
protocol StartupProcess {
    func run()
}

/// A convenience type used for running StartupProcesses.
/// Uses the Builder pattern for some coding eye candy.
final class StartupProcessService {
    init() { }

    /// Executes the passed-in StartupProcess by running it's "run()" method.
    /// - Parameter process: A StartupProcess instance, to be initiated.
    /// - Returns: Returns "self", as a means to chain invocations of StartupProcess instances.
    @discardableResult
    func execute(process: any StartupProcess) -> StartupProcessService {
        process.run()
        return self
    }
}

然后我們有一些流程

struct CrashlyticsProcess: StartupProcess {
    func run() {
        // Do stuff, like SDK initialization, etc.
    }
}

struct FirebaseProcess: StartupProcess {
    func run() {
        // Do stuff, like SDK initialization, etc.
    }
}

struct AppearanceCustomizationProcess: StartupProcess {
    func run() {
        // Do stuff, like SDK initialization, etc.
    }
}

最后,運行它們

@main
struct TheApp: App {
    init() {
        initiateStartupProcesses()
    }

    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

private extension TheApp {
    func initiateStartupProcesses() {
        StartupProcessService()
            .execute(process: ExampleProcess())
            .execute(process: FirebaseProcess())
            .execute(process: AppearanceCustomizationProcess)
    }
}

看起來很漂亮而且超級干凈。

我看到很多解決方案init被用作didFinishLaunching 但是, didFinishLaunchingApp結構的init之后被調用。

相反,我們可以創建一個塊來在調用didFinishLaunching時通知我們。 這允許在 SwiftUI 世界中保留更多代碼(而不是在AppDelegate中)。

class AppDelegate: NSObject, UIApplicationDelegate {

  var didFinishLaunching: ((AppDelegate) -> Void)?

  func application(
    _ application: UIApplication,
    didFinishLaunchingWithOptions
      launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil
  ) -> Bool {
    didFinishLaunching?(self)
    return true
  }
}

@main
struct MyApp: App {
  @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate

  @ObservedObject private var applicationModel = ApplicationModel()

  // `init` gets called BEFORE `didFinishLaunchingWithOptions`
  init() {

    // Subscribe to get a `didFinishLaunching` call
    appDelegate.didFinishLaunching = { [weak applicationObject] appDelegate in

      // Setup any application code...
      applicationModel?.setup()
    }
  }

  var body: some Scene {
    return WindowGroup {
      if applicationObject.isUserLoggedIn {
        LoggedInView()
      } else {
        LoggedOutView()
      }
    }
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM