In-App Purchases · Listing the Products | raywenderlich.com


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/1304447-in-app-purchases/lessons/10

At 7:17 you set the completion handler to none and in previous line you assigned it (true, response.products). Why did you do that.

What I did was first call the completion handler, and then I set the completion handler to none. That clears out the closure. Otherwise, we would hold on it until another request. By setting it to none, we are reclaiming that unused memory. I hope that makes sense.

In iOS14 and Xcode 12 I am getting an error that self?.tableView.reloadData() in requestAllProducts() needs to happen on the main thread.

Me too. I’m having errors as well and the products aren’t showing up.
Just spent 50$ and a day on this tutorial and it doesn’t even work. Very frustrating.

The good news is that we are currently editing the updated version of this course and should be released soon.

Regarding the thread error, the call should be in a DispatchQueue as follows:

DispatchQueue.main.async { [weak self] in
    self?.tableView.reloadData()
}

Note there could be lots of reasons why the products may not be showing up. If you have a specific error, feel free to post here or let me know what you’ve been encountering.

Thanks!

Hi, thanks for the quick response! Really appreciate it!

Do you mean like this:

 @objc func requestAllProducts() {
     OwlProducts.store.requestProducts {
       [weak self] success, products in
       if success, let products = products {
         self?.products = products
         DispatchQueue.main.async { [weak self] in
             self?.tableView.reloadData()
         }
       }
       self?.refreshControl.endRefreshing()
     }
   }

Regarding the errors, this is my log:

=================================================================
Main Thread Checker: UI API called on a background thread: -[UIRefreshControl endRefreshing]
PID: 3967, TID: 975575, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4 InsomniOwl 0x0000000104a84804 $s10InsomniOwl20MasterViewControllerC18requestAllProductsyyFySb_SaySo9SKProductCGSgtcfU_ + 1308
5 InsomniOwl 0x0000000104a8e220 $s10InsomniOwl9IAPHelperC15productsRequest_10didReceiveySo010SKProductsE0C_So0H8ResponseCtF + 232
6 InsomniOwl 0x0000000104a8e2d4 $s10InsomniOwl9IAPHelperC15productsRequest_10didReceiveySo010SKProductsE0C_So0H8ResponseCtFTo + 84
7 StoreKit 0x00000001c71e8a20 C15DD601-BCBA-3A5F-815D-CC6A70B50B80 + 100896
8 libdispatch.dylib 0x0000000104cf3bcc _dispatch_call_block_and_release + 32
9 libdispatch.dylib 0x0000000104cf56c0 _dispatch_client_callout + 20
10 libdispatch.dylib 0x0000000104cf80ec _dispatch_queue_override_invoke + 952
11 libdispatch.dylib 0x0000000104d08ae0 _dispatch_root_queue_drain + 364
12 libdispatch.dylib 0x0000000104d09488 _dispatch_worker_thread2 + 140
13 libsystem_pthread.dylib 0x00000001f48dd7d8 pthread_wqthread + 216
14 libsystem_pthread.dylib 0x00000001f48e476c start_wqthread + 8
2021-02-16 20:48:39.368630+0200 InsomniOwl[3967:975575] [reports] Main Thread Checker: UI API called on a background thread: -[UIRefreshControl endRefreshing]
PID: 3967, TID: 975575, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4 InsomniOwl 0x0000000104a84804 $s10InsomniOwl20MasterViewControllerC18requestAllProductsyyFySb_SaySo9SKProductCGSgtcfU
+ 1308
5 InsomniOwl 0x0000000104a8e220 $s10InsomniOwl9IAPHelperC15productsRequest_10didReceiveySo010SKProductsE0C_So0H8ResponseCtF + 232
6 InsomniOwl 0x0000000104a8e2d4 $s10InsomniOwl9IAPHelperC15productsRequest_10didReceiveySo010SKProductsE0C_So0H8ResponseCtFTo + 84
7 StoreKit 0x00000001c71e8a20 C15DD601-BCBA-3A5F-815D-CC6A70B50B80 + 100896
8 libdispatch.dylib 0x0000000104cf3bcc _dispatch_call_block_and_release + 32
9 libdispatch.dylib 0x0000000104cf56c0 _dispatch_client_callout + 20
10 libdispatch.dylib 0x0000000104cf80ec _dispatch_queue_override_invoke + 952
11 libdispatch.dylib 0x0000000104d08ae0 _dispatch_root_queue_drain + 364
12 libdispatch.dylib 0x0000000104d09488 _dispatch_worker_thread2 + 140
13 libsystem_pthread.dylib 0x00000001f48dd7d8 _pthread_wqthread + 216
14 libsystem_pthread.dylib 0x00000001f48e476c start_wqthread + 8
2021-02-16 20:48:50.918575+0200 InsomniOwl[3967:975575] [Assert] UIView animation API is being called from a background thread. Performing any operation from a background thread on UIView or a subclass is not supported and may result in unexpected and insidious behavior.
2021-02-16 20:49:43.632544+0200 InsomniOwl[3967:975575] This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
Stack:(
0 CoreAutoLayout 0x00000001be0f4110 942D516F-2BE6-3587-9821-A450F305F686 + 65808
1 CoreAutoLayout 0x00000001be0f3edc 942D516F-2BE6-3587-9821-A450F305F686 + 65244
2 CoreAutoLayout 0x00000001be0f39b4 942D516F-2BE6-3587-9821-A450F305F686 + 63924
3 CoreAutoLayout 0x00000001be0eef9c 942D516F-2BE6-3587-9821-A450F305F686 + 44956
4 UIKitCore 0x00000001abd2f394 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 17912724
5 UIKitCore 0x00000001abd2ff24 8518EAE3-832B-3FF0-9FA5-9DBE3041F26C + 17915684
6 QuartzCore 0x00000001ac24a644 8510F139-0824-3686-A9AA-3E198539A021 + 1439300
7 QuartzCore 0x00000001ac24ab18 8510F139-0824-3686-A9AA-3E198539A021 + 1440536
8 QuartzCore 0x00000001ac25f30c 8510F139-0824-3686-A9AA-3E198539A021 + 1524492
9 QuartzCore 0x00000001ac1a4640 8510F139-0824-3686-A9AA-3E198539A021 + 759360
10 QuartzCore 0x00000001ac1cfb08 8510F139-0824-3686-A9AA-3E198539A021 + 936712
11 QuartzCore 0x00000001ac1d0354 8510F139-0824-3686-A9AA-3E198539A021 + 938836
12 libsystem_pthread.dylib 0x00000001f48e3e6c C939A2AB-D3B1-3B0A-83C5-7CE2F4F339A9 + 40556
13 libsystem_pthread.dylib 0x00000001f48dbd10 C939A2AB-D3B1-3B0A-83C5-7CE2F4F339A9 + 7440
14 libsystem_pthread.dylib 0x00000001f48ddb34 C939A2AB-D3B1-3B0A-83C5-7CE2F4F339A9 + 15156
15 libsystem_pthread.dylib 0x00000001f48dd8a4 _pthread_wqthread + 420
16 libsystem_pthread.dylib 0x00000001f48e476c start_wqthread + 8
)
2021-02-16 20:49:43.637402+0200 InsomniOwl[3967:975575] *** 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.’
*** First throw call stack:
(0x1a8e2d86c 0x1bde48c50 0x1be0f4208 0x1be0f3edc 0x1be0f39b4 0x1be0eef9c 0x1abd2f394 0x1abd2ff24 0x1ac24a644 0x1ac24ab18 0x1ac25f30c 0x1ac1a4640 0x1ac1cfb08 0x1ac1d0354 0x1f48e3e6c 0x1f48dbd10 0x1f48ddb34 0x1f48dd8a4 0x1f48e476c)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

Glad to help!

Some background as to what is happening based on the log you posted. The code was trying to update the user interface from a background thread. This will break the UI so anytime you need to update the user interface from the background or get that kind of error message, you need to call it on the main thread which is what that DispatchQueue code does.

So with that in mind, I’d update it to the following:

 @objc func requestAllProducts() {
     OwlProducts.store.requestProducts {
       [weak self] success, products in
       if success, let products = products {
         self?.products = products
         DispatchQueue.main.async { 
             self?.tableView.reloadData()
         }
       }
       DispatchQueue.main.async {
           self?.refreshControl.endRefreshing()
       }
     }
   }

I removed the [weak self] from the DispatchQueue code because you are already capturing self as weak in requestProducts.

Also note that I put the DispatchQueue code around the refresh control since that’s a UI element that also needs to be updated on the main thread. That should resolve that background error. Hopefully with that fix, fingers crossed, you should get products back. Let me know if you run into any other issues.

Cheers!

Hi!
Again, thanks for the quick reply!

Indeed now there are no errors or crashes, but the products still don’t appear.
I’ve gone over the troubleshooting video but it seems like everything is in place.

I’ve also added print commands so I know that “requestProducts” method in IAPHelper is being called and the response is received successfuly. :thinking::thinking:

EDIT: So far I’ve managed to narrow it down a bit. It appears the response is received but “response.products” is an empty array.

Interestingly I still get this error after I terminate the app run:

=================================================================
Main Thread Checker: UI API called on a background thread: -[UIRefreshControl endRefreshing]
PID: 93758, TID: 6666088, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4 InsomniOwl 0x000000010cd0980a $s10InsomniOwl20MasterViewControllerC18requestAllProductsyyFySb_SaySo9SKProductCGSgtcfU_ + 1130
5 InsomniOwl 0x000000010cd13b11 $s10InsomniOwl9IAPHelperC7request_16didFailWithErrorySo9SKRequestC_s0H0_ptF + 209
6 InsomniOwl 0x000000010cd13bc4 $s10InsomniOwl9IAPHelperC7request_16didFailWithErrorySo9SKRequestC_s0H0_ptFTo + 100
7 StoreKit 0x000000010df12378 __27-[SKProductsRequest _start]_block_invoke_2 + 120
8 libdispatch.dylib 0x000000011128d7ec _dispatch_call_block_and_release + 12
9 libdispatch.dylib 0x000000011128e9c8 _dispatch_client_callout + 8
10 libdispatch.dylib 0x0000000111290e46 _dispatch_queue_override_invoke + 1032
11 libdispatch.dylib 0x00000001112a0508 _dispatch_root_queue_drain + 351
12 libdispatch.dylib 0x00000001112a0e6d _dispatch_worker_thread2 + 135
13 libsystem_pthread.dylib 0x00007fff61167453 pthread_wqthread + 244
14 libsystem_pthread.dylib 0x00007fff61166467 start_wqthread + 15
2021-02-16 20:02:53.298327+0200 InsomniOwl[93758:6666088] [reports] Main Thread Checker: UI API called on a background thread: -[UIRefreshControl endRefreshing]
PID: 93758, TID: 6666088, Thread name: (none), Queue name: com.apple.root.default-qos, QoS: 0
Backtrace:
4 InsomniOwl 0x000000010cd0980a $s10InsomniOwl20MasterViewControllerC18requestAllProductsyyFySb_SaySo9SKProductCGSgtcfU
+ 1130
5 InsomniOwl 0x000000010cd13b11 $s10InsomniOwl9IAPHelperC7request_16didFailWithErrorySo9SKRequestC_s0H0_ptF + 209
6 InsomniOwl 0x000000010cd13bc4 $s10InsomniOwl9IAPHelperC7request_16didFailWithErrorySo9SKRequestC_s0H0_ptFTo + 100
7 StoreKit 0x000000010df12378 __27-[SKProductsRequest _start]_block_invoke_2 + 120
8 libdispatch.dylib 0x000000011128d7ec _dispatch_call_block_and_release + 12
9 libdispatch.dylib 0x000000011128e9c8 _dispatch_client_callout + 8
10 libdispatch.dylib 0x0000000111290e46 _dispatch_queue_override_invoke + 1032
11 libdispatch.dylib 0x00000001112a0508 _dispatch_root_queue_drain + 351
12 libdispatch.dylib 0x00000001112a0e6d _dispatch_worker_thread2 + 135
13 libsystem_pthread.dylib 0x00007fff61167453 _pthread_wqthread + 244
14 libsystem_pthread.dylib 0x00007fff61166467 start_wqthread + 15
2021-02-16 20:02:53.367020+0200 InsomniOwl[93758:6666088] [Assert] UIView animation API is being called from a background thread. Performing any operation from a background thread on UIView or a subclass is not supported and may result in unexpected and insidious behavior.
2021-02-16 20:02:55.798814+0200 InsomniOwl[93758:6666090] [Assert] UIView animation API is being called from a background thread. Performing any operation from a background thread on UIView or a subclass is not supported and may result in unexpected and insidious behavior.
2021-02-16 20:03:00.801875+0200 InsomniOwl[93758:6666088] This application is modifying the autolayout engine from a background thread after the engine was accessed from the main thread. This can lead to engine corruption and weird crashes.
Stack:(
0 CoreAutoLayout 0x0000000112c9cb9b _AssertAutoLayoutOnAllowedThreadsOnly + 190
1 CoreAutoLayout 0x0000000112c9c926 -[NSISEngine _optimizeWithoutRebuilding] + 54
2 CoreAutoLayout 0x0000000112c9c459 -[NSISEngine optimize] + 92
3 CoreAutoLayout 0x0000000112c978c4 -[NSISEngine performPendingChangeNotifications] + 82
4 UIKitCore 0x000000011ba58812 -[UIView _wantsReapplicationOfAutoLayoutWithLayoutDirtyOnEntry:] + 173
5 UIKitCore 0x000000011ba59563 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 3019
6 QuartzCore 0x000000010e118c2b -[CALayer layoutSublayers] + 258
7 QuartzCore 0x000000010e11f19d _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575
8 QuartzCore 0x000000010e12af3f _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 65
9 QuartzCore 0x000000010e06a44c _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496
10 QuartzCore 0x000000010e0a1233 _ZN2CA11Transaction6commitEv + 783
11 QuartzCore 0x000000010e0a1a36 _ZN2CA11Transaction14release_threadEPv + 210
12 libsystem_pthread.dylib 0x00007fff611689b8 _pthread_tsd_cleanup + 487
13 libsystem_pthread.dylib 0x00007fff6116af99 _pthread_exit + 70
14 libsystem_pthread.dylib 0x00007fff61168764 pthread_exit + 0
15 libsystem_pthread.dylib 0x00007fff61167535 _pthread_wqthread + 470
16 libsystem_pthread.dylib 0x00007fff61166467 start_wqthread + 15
)
2021-02-16 20:03:00.805056+0200 InsomniOwl[93758:6666088] *** 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.’
*** First throw call stack:
(
0 CoreFoundation 0x000000010eb3daf6 __exceptionPreprocess + 242
1 libobjc.A.dylib 0x000000010e9cde78 objc_exception_throw + 48
2 CoreAutoLayout 0x0000000112c9cc89 -[NSISEngine tryToOptimizeReturningMutuallyExclusiveConstraints] + 0
3 CoreAutoLayout 0x0000000112c9c926 -[NSISEngine _optimizeWithoutRebuilding] + 54
4 CoreAutoLayout 0x0000000112c9c459 -[NSISEngine optimize] + 92
5 CoreAutoLayout 0x0000000112c978c4 -[NSISEngine performPendingChangeNotifications] + 82
6 UIKitCore 0x000000011ba58812 -[UIView _wantsReapplicationOfAutoLayoutWithLayoutDirtyOnEntry:] + 173
7 UIKitCore 0x000000011ba59563 -[UIView(CALayerDelegate) layoutSublayersOfLayer:] + 3019
8 QuartzCore 0x000000010e118c2b -[CALayer layoutSublayers] + 258
9 QuartzCore 0x000000010e11f19d _ZN2CA5Layer16layout_if_neededEPNS_11TransactionE + 575
10 QuartzCore 0x000000010e12af3f _ZN2CA5Layer28layout_and_display_if_neededEPNS_11TransactionE + 65
11 QuartzCore 0x000000010e06a44c _ZN2CA7Context18commit_transactionEPNS_11TransactionEdPd + 496
12 QuartzCore 0x000000010e0a1233 _ZN2CA11Transaction6commitEv + 783
13 QuartzCore 0x000000010e0a1a36 _ZN2CA11Transaction14release_threadEPv + 210
14 libsystem_pthread.dylib 0x00007fff611689b8 _pthread_tsd_cleanup + 487
15 libsystem_pthread.dylib 0x00007fff6116af99 _pthread_exit + 70
16 libsystem_pthread.dylib 0x00007fff61168764 pthread_exit + 0
17 libsystem_pthread.dylib 0x00007fff61167535 _pthread_wqthread + 470
18 libsystem_pthread.dylib 0x00007fff61166467 start_wqthread + 15
)
libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)

The hard part in all of this is determining why products aren’t returning. The most obvious is the product names in your app must exactly match the products you put in App Store Connect.

com.razeware.iap.HappyOwl ← app store connect
com.razeware.iap.HappyOwl ← your app

Casing matters. Each identifier must be exactly as you have it in App Store Connect. These two are different:

com.razeware.iap.HappyOwl
com.razeware.iap.happyowl

Next, your bundle identifier of your project must match the profiles in the developer center. Make sure you have your project using the correct signing. Also Remember, you must be using a paid apple developer account. This won’t work for a free account.

Make sure your in app purchases are ready for review in app store connect (you can get away with missing metadata)

All your agreements must be signed. Make sure to go to the agreements section and check every category.

Basically, you need to go over everything with a fine tooth comb. If just one thing is amiss, Apple won’t send you back the products. It’s frustrating - I was just there. If you continue to run into walls, the next best solution is to jump on RW Chat - the discord app. There are lots of iOS developers on there who may provide some additional guidance.

It looks like there was some kind of error on the AppStoreConnect’s side.
After refreshing the site, now it’s working!

I thought it might be a problem with localization since I’m not in the US, so I went to one of the non-consumables and add my localization. Thing is that after I did that all of the IAP appeared at once. And so I went back and removed my localization, and it’s still working perfectly fine!

Dmannit… go figure…

Sorry for wasting your time, and thanks again for the support! Very much appreciated!

No worries at all! Getting them to show up can be tricky. It’s probably the most frustrating part of the process since Apple gives zero feedback about why it failed. It’s all detective work. Thankfully, in Xcode 12 we can actually build them in the editor which is covered in the updated course which makes them easier to use.

In any case, congrats on working through it. Feel free to reach out to me if you get stuck again.

Cheers!