ios - 启动新屏幕时,带有Swift的Xcode中的线程错误

标签 ios swift amazon-web-services

用户登录到我的应用程序后,我将设置窗口,设置rootViewController和makeKeyAndVisible,并且在执行此操作时会出现Thread 9: signal SIGABRT错误。 FWIW,设置-[UIWindow initWithFrame:] must be used from main thread only时,我得到紫色警告self.window = UIWindow(frame: UIScreen.main.bounds)。请参阅下面的代码以查看我的设置。

代码在此处死于该错误-AppController.swift中下面self.window!.makeKeyAndVisible()函数中的launchWindow(aWindow: UIWindow?)

AppDelegate.swift

//
//  AppDelegate.swift


import UIKit
import AWSCognitoAuth
import AWSSNS
import AWSCognitoIdentityProvider
import UserNotifications
import ESTabBarController_swift
import AWSMobileClient

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {

    var window: UIWindow?
var navigationController: UINavigationController?
    var storyboard: UIStoryboard?
    var loginViewController: LoginViewController?
    var pool = AWSCognitoIdentityUserPool.init(forKey: "UserPool")

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {

        AppController.sharedInstance.enableCognitoClientWithAuthentication()

        // setup logging
//        pool.delegate = self
//        AWSDDLog.sharedInstance.logLevel = .verbose
//        let credentialsProvider = AWSCognitoCredentialsProvider(regionType: .USEast1,
//                                                                identityPoolId: Constants.APIKeys.AWSIdentityPoolID)
//
//        // setup service configuration
//        let serviceConfiguration = AWSServiceConfiguration(region: AWSRegionType.USEast1, credentialsProvider: credentialsProvider)
//
//        // create pool configuration
//        let poolConfiguration = AWSCognitoIdentityUserPoolConfiguration(clientId: Constants.APIKeys.AWSClientID,
//                                                                        clientSecret: Constants.APIKeys.AWSSecret,
//                                                                        poolId: Constants.APIKeys.AWSPoolID)
//        AWSServiceManager.default().defaultServiceConfiguration = serviceConfiguration
//        // initialize user pool client
//        AWSCognitoIdentityUserPool.register(with: serviceConfiguration, userPoolConfiguration: poolConfiguration, forKey: "UserPool")
//
//        pool.currentUser()?.getSession()
        // fetch the user pool client we initialized in above step
        //let pool = AWSCognitoIdentityUserPool(forKey: "UserPool")

        let signedIn = AWSMobileClient.sharedInstance().isSignedIn
        self.navigationController = UINavigationController()
        if !signedIn {
            navigationInit()
        }
//        } else {
//            AppController.sharedInstance.showLoggedInStateAndReturn(true)
//        }

                //pool.delegate = self
        self.window = UIWindow(frame: UIScreen.main.bounds)
        AppController.sharedInstance.launchInWindow(aWindow: self.window)

        return true
    }

    func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
        navigationInit()

        return true
    }

    func navigationInit() {

        let loginViewController = LoginViewController()
        self.navigationController!.pushViewController(loginViewController, animated: false)


    }

    //MARK: Push Notification

    func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {

        /// Attach the device token to the user defaults
        var token = ""
        for i in 0..<deviceToken.count {
            token = token + String(format: "%02.2hhx", arguments: [deviceToken[i]])
        }

        print(token)
        UserDefaults.standard.set(token, forKey: "deviceTokenForSNS")

        /// Create a platform endpoint. In this case, the endpoint is a
        /// device endpoint ARN
        let sns = AWSSNS.default()
        let request = AWSSNSCreatePlatformEndpointInput()
        request?.token = token
        request?.platformApplicationArn = Constants.APIKeys.AWSSSNSARN

        sns.createPlatformEndpoint(request!).continueWith(executor: AWSExecutor.mainThread(), block: { (task: AWSTask!) -> AnyObject? in
            if task.error != nil {
                print("Error: \(String(describing: task.error))")
            } else {
                let createEndpointResponse = task.result! as AWSSNSCreateEndpointResponse
                if let endpointArnForSNS = createEndpointResponse.endpointArn {
                    print("endpointArn: \(endpointArnForSNS)")
                    Settings.setPushArn(endpointArnForSNS)

                    NotificationCenter.default.post(name: NSNotification.Name(rawValue: "RegisteredForPush"), object: nil)

                }
            }

            return nil
        })
    }

    func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {

        let visible = window?.visibleViewController()

        if let data = userInfo["aps"] as? [AnyHashable: Any] {
            if let route = data["route"] as? String {
                switch route {
                case "matchRequested":
                    var projectId = ""
                    if let project = data["projectId"] as? String {
                        projectId = project
                    }
                    var matchId = ""
                    if let match = data["matchId"] as? String {
                        matchId = match
                    }
                    let projectMatches = MatchRequestedViewController(withNotificationPayload: projectId, matchId: matchId)
                    visible?.navigationController?.pushViewController(projectMatches, animated: true)

                case "projectDetails":
                    var projectId = ""
                    if let project = data["projectId"] as? String {
                        projectId = project
                    }
                    let projectMatches = ProjectDetailsViewController(withProject: TERMyProject(), orProjectId: projectId)
                    visible?.navigationController?.pushViewController(projectMatches, animated: true)
                case "matched":
                    var projectId = ""
                    if let project = data["projectId"] as? String {
                        projectId = project
                    }
                    var matchId = ""
                    if let match = data["matchId"] as? String {
                        matchId = match
                    }
                    var originProject: TERMyProject = TERMyProject()
                    var matchedProject: TERMatchedProject = TERMatchedProject()

                    AppController.sharedInstance.AWSClient?.projectsGet(id:projectId).continueWith(block: { (task: AWSTask) -> Any? in

                        if let error = task.error {
                            print("Error: \(error)")

                        } else if let result = task.result {
                            if result is NSDictionary {
                                DispatchQueue.main.async {
                                    let array = [result]
                                    let parsedProject: [TERMyProject] = TERMyProject.parseFromAPI(array:array as! [NSDictionary])
                                    for project in parsedProject {
                                        originProject = project
                                    }
                                    //                        self.initialSetup()
                                }
                                AppController.sharedInstance.AWSClient?.projectsGet(id:matchId).continueWith(block: { (task: AWSTask) -> Any? in

                                    if let error = task.error {
                                        print("Error: \(error)")

                                    } else if let result = task.result {
                                        if result is NSDictionary {
                                            DispatchQueue.main.async {
                                                let array = [result]
                                                let parsedProject: [TERMatchedProject] = TERMatchedProject.parseFromAPI(array:array as! [NSDictionary])
                                                for project in parsedProject {
                                                    matchedProject = project
                                                }
                                                let projectMatches = MatchedViewController(withProject: originProject, match: matchedProject, isComplete: false)
                                                visible?.navigationController?.pushViewController(projectMatches, animated: true)
                                            }

                                        }
                                    }
                                    return nil
                                })
                            }
                        }
                        return nil
                    })



                default:
                    break
                }

            }
        }
    }

    func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
        print(error.localizedDescription)
    }

    // Called when a notification is delivered to a foreground app.
    @available(iOS 10.0, *)
    func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
        print("User Info = ",notification.request.content.userInfo)
        completionHandler([.alert, .badge, .sound])
    }

    //MARK: Boiler-plate methods

    func applicationWillResignActive(_ application: UIApplication) {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
    }

    func applicationDidEnterBackground(_ application: UIApplication) {
        // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
        // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
    }

    func applicationWillEnterForeground(_ application: UIApplication) {
        // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    }

    func applicationDidBecomeActive(_ application: UIApplication) {

    }

    func applicationWillTerminate(_ application: UIApplication) {
        // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
    }

}


extension AppDelegate: AWSCognitoIdentityInteractiveAuthenticationDelegate {

//    func startPasswordAuthentication() -> AWSCognitoIdentityPasswordAuthentication {
//        if (self.navigationController == nil) {
//
//            self.navigationController = self.storyboard?.instantiateViewController(withIdentifier: "LoginViewController") as? UINavigationController
//        }
//
//        if (self.loginViewController == nil) {
//            self.loginViewController = self.navigationController?.viewControllers[0] as? LoginViewController
//        }
//
//        DispatchQueue.main.async {
//            self.navigationController!.popToRootViewController(animated: true)
//            if (!self.navigationController!.isViewLoaded
//                || self.navigationController!.view.window == nil) {
//                self.window?.rootViewController?.present(self.navigationController!,
//                                                         animated: true,
//                                                         completion: nil)
//            }
//
//        }
//        return self.loginViewController!
//    }


}

// MARK:- AWSCognitoIdentityRememberDevice protocol delegate

extension AppDelegate: AWSCognitoIdentityRememberDevice {
    func didCompleteStepWithError(_ error: Error?) {

    }


    func getRememberDevice(_ rememberDeviceCompletionSource: AWSTaskCompletionSource<NSNumber>) {


    }

}
extension UIWindow {

    func visibleViewController() -> UIViewController? {
        if let rootViewController: UIViewController = self.rootViewController {
            return UIWindow.getVisibleViewControllerFrom(vc: rootViewController)
        }
        return nil
    }

    class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController {

        switch(vc){
        case is UINavigationController:
            let navigationController = vc as! UINavigationController
            return UIWindow.getVisibleViewControllerFrom( vc: navigationController.visibleViewController!)
            break;

        case is UITabBarController:
            let tabBarController = vc as! UITabBarController
            return UIWindow.getVisibleViewControllerFrom(vc: tabBarController.selectedViewController!)
            break;

        default:
            if let presentedViewController = vc.presentedViewController {
                //print(presentedViewController)
                if let presentedViewController2 = presentedViewController.presentedViewController {
                    return UIWindow.getVisibleViewControllerFrom(vc: presentedViewController2)
                }
                else{
                    return vc;
                }
            }
            else{
                return vc;
            }
            break;
        }

    }


}



AppController.swift
    func launchInWindow(aWindow: UIWindow?){

        self.window = aWindow

        self.initializeSDKs()
        self.globalCustomization()

        self.AWSUnAuthedClient.apiKey = Constants.APIKeys.AWSAPIKey


        self.window!.rootViewController = self.showLoggedInStateAndReturn(true)
        self.window!.makeKeyAndVisible()

    }

    func initializeSDKs() {

        // Google places
        GMSPlacesClient.provideAPIKey(Constants.APIKeys.GooglePlaces)
    }

    func globalCustomization() {
        self.styleNavigationBar()
    }

    @discardableResult func showLoggedInStateAndReturn(_ shouldReturn: Bool) -> UIViewController? {

        //AppController.sharedInstance.enableCognitoClientWithAuthentication()
        //self.registerForPush()

        self.tabBarController = ESTabBarController()
        //tabBarController.delegate = delegate
        self.tabBarController?.title = "Irregularity"
        self.tabBarController?.tabBar.shadowImage = UIImage.image(with: UIColor("FFFFFF", alpha: 0.0)!)
        self.tabBarController?.tabBar.backgroundImage = UIImage.image(with: UIColor("2A2A27")!)
        self.tabBarController?.shouldHijackHandler = {
            tabbarController, viewController, index in
            if index == 1 {
                return true
            }
            return false
        }

            self.tabBarController?.didHijackHandler = {
            [weak tabBarController] tabbarController, viewController, index in

            DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                let newProjectNavCon = UINavigationController(rootViewController: NewProjectViewController())
                newProjectNavCon.hero.isEnabled = true
                newProjectNavCon.setNavigationBarHidden(true, animated: false)
                newProjectNavCon.hero.navigationAnimationType = .fade
                tabBarController?.present(newProjectNavCon, animated: true, completion: nil)
            }
        }

        let centerVC = UINavigationController(rootViewController: HomeViewController())

        let v1 = centerVC
        let v2 = BaseViewController()
        let v3 = UINavigationController(rootViewController: ProfileViewController())

        v1.tabBarItem = ESTabBarItem.init(TabBarBouncesContentView(), title: "Projects", image: UIImage(named: "tabBar"), selectedImage: UIImage(named: "tabBar"))
        v2.tabBarItem = ESTabBarItem.init(TabBarIrregularityContentView(), title: nil, image: UIImage(named: "tabBarPlusButton"), selectedImage: UIImage(named: "tabBarPlusButton"))
        v3.tabBarItem = ESTabBarItem.init(TabBarBouncesContentView(), title: "Profile", image: UIImage(named: "tabBarProfile"), selectedImage: UIImage(named: "tabBarProfile"))

        self.tabBarController?.setViewControllers([v1, v2, v3], animated: true)

        if shouldReturn {
            return self.tabBarController
        } else {
            self.window?.rootViewController = self.tabBarController
            return nil
        }

    }

最佳答案

您应该尝试执行main thread中的代码:

func launchInWindow(aWindow: UIWindow?){
    self.window = aWindow
    self.initializeSDKs()
    self.globalCustomization()
    self.AWSUnAuthedClient.apiKey = Constants.APIKeys.AWSAPIKey

    DispatchQueue.main.async {
        self.window!.rootViewController = self.showLoggedInStateAndReturn(true)
        self.window!.makeKeyAndVisible()
    }
}

另外,在AppDelegate.swift的这一部分中,您的问题代码库看起来有些奇怪:
self.window = UIWindow(frame: UIScreen.main.bounds) //-- Purple warning here
AppController.sharedInstance.launchInWindow(aWindow: self.window)

return true

看起来这三行代码不在函数中,而是在类范围中,这很奇怪,您不应该对其进行编译。可能您粘贴的代码错误?

关于ios - 启动新屏幕时,带有Swift的Xcode中的线程错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57423751/

相关文章:

iphone - 父 ViewController 在内存警告时释放

Swift:在多个范围之间生成随机数

xcode - swift UITesting 错误 : Invalid escape sequence in literal.\U201c

amazon-web-services - 尝试下载文件时禁止从 s3 获取 403

amazon-web-services - 如何使用 AWS CLI 设置加密的 Lambda 环境变量?

ios - 当有延迟并在 Collection View 中执行批量更新时,UIView.animate 中的 self 是否应该很弱?

ios - 如果 objectForKey 包含单个值,则在计数时抛出异常

ios - Swift 3 检查使用了哪个转场

swift - 如何在 SwiftUI 中从登录 View 转换为 tabView

amazon-web-services - 使用 CFN 的 SNS 指标