【iOS】iOS13からSKProductsRequestのDelegateメソッドがメインスレッドで呼ばれなくなった

はじめに

In App Purchaseを実装する際にApp Storeに課金Productを登録し、アプリからそのプロダクトの情報を取得します。 具体的には、下記のようにSKProductsRequestを作成し、取得したい課金プロダクトのIdentifiersをSetで指定、通信結果を func productsRequest(request: SKProductsRequest, didReceiveResponse response: SKProductsResponse)で受け取ります。(※補足ですがRequestが解放されないよう強参照で保持するようAppleのDocumentに記載があります)

ただ、このメソッドの挙動がiOS13以降で変わったようなのでその内容を記載します。

private var request: SKProducstRequest?
request = SKProductsRequest(productIdentifiers: Set(productIdentifiers))
request?.delegate = self
request?.start()

環境設定

以下の環境を使用しています。

  • iOS 13.1.2
  • Xcode11.1.0

どう変わったか

端的にまとめると下記2つのメソッドがメインスレッドで実行されなくなりました。 具体的にはcom.apple.root.default-qos (concurrent)で実行されているようです。

func productsRequest(SKProductsRequest, didReceive: SKProductsResponse)
func request(SKRequest, didFailWithError: Error)

したがって今までメインスレッドで実行されることを想定していた実装の場合は注意が必要です。

対応方法

各メソッド内の処理を明示的にメインスレッドで実行するようにすれば大丈夫です。

func productsRequest(SKProductsRequest, didReceive: SKProductsResponse) {
    DispatchQueue.main.async {
        // なんらかの処理
    }
}

func request(SKRequest, didFailWithError: Error) {
    DispatchQueue.main.async {
        // なんらかの処理
    }
}

備考

自分で確かめていませんが、MacOSでの実行時は上記のメソッドは元々メインスレッドで実行されていなかったようです。iOS13以降ではProject CatalystによってiOSアプリとMacOSアプリのソースコードを共通化する仕組みが進められており、そのあたりの影響でこのような挙動の変更が発生したのかもしれません。(定かではないです)

参考