从按钮加载另一个故事板时故事板崩溃

时间:2021-01-25 20:58:36

标签: swift model-view-controller storyboard

func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
    hideActivity()
    let products = response.products
    if products.count > 0{
        let controller = HAPurchaseViewController.instantiate() // crashes here
        controller.categories = dataManager.paidCategories()
        controller.products = products
        self.navigationController?.pushViewController(controller, animated: true)
    }
    else{
        DispatchQueue.main.async { [weak self] in
            let alertController = UIAlertController(title: "Oops!", message: "Unable to load or products not found, please try again later", preferredStyle: .alert)
            let okAction = UIAlertAction(title: "Ok", style: .default)
            alertController.addAction(okAction)
            self?.present(alertController, animated: true)
        }
    }
}

此扩展程序适用于其他任何地方,除非我使用它加载我的应用内购买视图控制器。

import Foundation
import UIKit

protocol Storyboarded {
    static func instantiate() -> Self
}


extension Storyboarded where Self: UIViewController {
    static func instantiate() -> Self {
        let id = String(describing: self)
        let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
        if #available(iOS 13.0, *) {
            return storyboard.instantiateViewController(identifier: id) as! Self // App crash here when loading storyboard
        } else {
            return storyboard.instantiateViewController(withIdentifier: id) as! Self
        }
    }
    static func value() -> Self {
        return UIViewController() as! Self
    }
}


================================================================= 
Main Thread Checker: UI API called on a background thread: -[UIViewController initWithCoder:] > PID: 13525, TID: 4347723, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:

根据SO的建议,我更新了代码

extension Storyboarded where Self: UIViewController {
    static func instantiate() -> Self {
        DispatchQueue.main.async {
            let id = String(describing: self)
            let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
            if #available(iOS 13.0, *) {
                return storyboard.instantiateViewController(identifier: id) as! Self
            } else {
                return storyboard.instantiateViewController(withIdentifier: id) as! Self
            }
        }
    }
    static func value() -> Self {
        return UIViewController() as! Self
    }
}

enter image description here

1 个答案:

答案 0 :(得分:1)

问题出在这里:

func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
    // ... this is a background thread!
}

所以此时你不能做任何涉及接口的事情,而不进入主线程。您实际上已经在第二部分这样做了:

hideActivity()
let products = response.products
if products.count > 0{
    let controller = HAPurchaseViewController.instantiate() 
    controller.categories = dataManager.paidCategories()
    controller.products = products
    self.navigationController?.pushViewController(controller, animated: true)
}
else{
    // LOOK! You are already doing it here
    DispatchQueue.main.async { [weak self] in
        let alertController = UIAlertController(title: "Oops!", message: "Unable to load or products not found, please try again later", preferredStyle: .alert)
        let okAction = UIAlertAction(title: "Ok", style: .default)
        alertController.addAction(okAction)
        self?.present(alertController, animated: true)
    }
}

嗯?所以在第一部分做同样的事情!

hideActivity()
let products = response.products
if products.count > 0{
    DispatchQueue.main.async { [weak self] in
        let controller = HAPurchaseViewController.instantiate() 
        controller.categories = dataManager.paidCategories()
        controller.products = products
        self?.navigationController?.pushViewController(controller, animated: true)
    }
} else {
    DispatchQueue.main.async { [weak self] in
        let alertController = UIAlertController(title: "Oops!", message: "Unable to load or products not found, please try again later", preferredStyle: .alert)
        let okAction = UIAlertAction(title: "Ok", style: .default)
        alertController.addAction(okAction)
        self?.present(alertController, animated: true)
    }
}