Hi,
After ios 13 release I retested my app and I am getting an error which was not on previous versions of ios:
Main Thread Checker: UI API called on a background thread: -[UIPageViewController setViewControllers:direction:animated:completion:]
and
Main Thread Checker: UI API called on a background thread: -[UIPageViewController setViewControllers:direction:animated:completion:]
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Modifications to the layout engine must not be performed from a background thread after it has been accessed from the main thread.'
Here is the code:
@IBAction func nextButtonTapped(_ sender: UIButton) {
let onboardingPager = self.parent as! OnboardingPager
var purchased = Bool(false)
DoctorSugarProducts.store.requestProducts{ [weak self] success, products in
guard let self = self else { return }
if success {
//self.products = products!
for product in products! {
if DoctorSugarProducts.store.isProductPurchased(product.productIdentifier) {
purchased = true
}
}
if purchased == false {
//onboardingPager.transition(from: onboardingPager.getStepZero(), to: onboardingPager.getStepOne(), duration: 0, options: [], animations: nil, completion: nil)
onboardingPager.setViewControllers([onboardingPager.getStepOne()], direction: .forward, animated: true, completion: nil)
} else {
onboardingPager.setViewControllers([onboardingPager.getStepTwo()], direction: .forward, animated: true, completion: nil)
}
} else {
onboardingPager.setViewControllers([onboardingPager.getStepTwo()], direction: .forward, animated: true, completion: nil)
}
}
}
Line causing the problem is the last line: onboardingPager.setViewControllers([onboardingPager.getStepTwo()], direction: .forward, animated: true, completion: nil)
Products requested are products from SKProductsRequestDelegate.
Does anyone have similar problem and knows what to do about it?
I have not experienced exactly the same issue, but the fix seems to be clear.
Do all the UI API calls and possibly thread-unsafe operations on the main thread.
Something like this:
@IBAction func nextButtonTapped(_ sender: UIButton) {
let onboardingPager = self.parent as! OnboardingPager
DoctorSugarProducts.store.requestProducts{ success, products in
DispatchQueue.main.async {
if success {
let purchased = (products ?? []).contains {
DoctorSugarProducts.store.isProductPurchased($0.productIdentifier)
}
if !purchased {
onboardingPager.setViewControllers([onboardingPager.getStepOne()], direction: .forward, animated: true, completion: nil)
} else {
onboardingPager.setViewControllers([onboardingPager.getStepTwo()], direction: .forward, animated: true, completion: nil)
}
} else {
onboardingPager.setViewControllers([onboardingPager.getStepTwo()], direction: .forward, animated: true, completion: nil)
}
}
}
}
Some changes other that putting `DispatchQueue.main.async {...}` are just for my preference, but I believe you have no need to use `[weak self]` in your case.