Hi there,
It seems I'm getting crashes in the Apple Music subscription view sometimes. Couldn't figure out why.
crash_info_entry_0 _MusicKit_SwiftUI/MusicSubscriptionOffer.swift:73: Fatal error: Unexpectedly changed musicSubscriptionOffer's isPresented binding to true while internal presentation state is loading(MusicSubscriptionOffer.Options(messageIdentifier: .join, itemID: 331661274, affiliateToken: ....)).
It's important to note I am displaying it from UIKit ObjC and so I had to go through some hoops in order to get this to working.
Here's the relevant code:
//
// MusicSubscriptionOfferView.swift
//
import Foundation
import MusicKit
import Combine
import SwiftUI
struct MusicSubscriptionOfferView: View {
@StateObject var viewModel = MusicSubscriptionOfferViewModel()
var body: some View {
EmptyView()
.musicSubscriptionOffer(
isPresented: $viewModel.isShowingOffer,
options: viewModel.offerOptions
)
}
}
class MusicSubscriptionOfferViewModel: NSObject, ObservableObject {
@Published var isShowingOffer = false
static var musicItemID: MusicItemID?
var canBecomeSubscriber = false
var offerOptions: MusicSubscriptionOffer.Options {
get {
var options = MusicSubscriptionOffer.Options()
options.affiliateToken = "..."
options.itemID = MusicSubscriptionOfferViewModel.musicItemID
return options
}
}
var subscriptions = Set<AnyCancellable>()
override init() {
super.init()
Task {
for await subscription in MusicSubscription.subscriptionUpdates {
MyApp.sharedInstance().canBecomeSubscriber = subscription.canBecomeSubscriber
}
}
NotificationCenter.default
.publisher(for: NSNotification.Name(K_SHOW_APPLE_MUSIC_SUBSCRIPTION))
.sink { [weak self] _ in
self!.isShowingOffer = true
}
.store(in: &subscriptions)
}
}
MusicSubscriptionOfferViewModel
is initiated on launch, so MyApp.sharedInstance().canBecomeSubscriber
receives a value upon launch.
and:
@objcMembers
final class MusicOfferProxyViewController: UIHostingController<MusicSubscriptionOfferView> {
required init() {
super.init(rootView: MusicSubscriptionOfferView())
}
@objc required dynamic init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
From the UIKit view controller:
MusicKitInterop* musicKitObject = [[MusicKitInterop alloc] init];
[self.view addSubview:musicKitObject.musicOfferProxyViewController.view];
[self addChildViewController:musicKitObject.musicOfferProxyViewController];
self.musicKitInterop = musicKitObject;
class MusicKitInterop: NSObject {
var musicOfferVC: MusicOfferProxyViewController
override init() {
musicOfferVC = MusicOfferProxyViewController()
}
@objc func musicOfferProxyViewController() -> UIViewController {
return musicOfferVC
}
@objc func canBecomeSubscriber() -> Bool {
return MyApp.sharedInstance().canBecomeSubscriber
}
}