Is there a way to specify where the backBarButtonItem.menu gets its label from for a screen. The WWDC video says that it selects the best from title, backButtonTitle and backbarbuttonItem.title. We want to specify that it comes from backButtonTitle because for some of our screens we set navigationItem.backBarButtonItem = UIBarButtonItem(title: "", style: .plain, target: nil, action: nil)
it seems to always use the backBarButton.title if it is there so we are getting an empty string in our back button context menu.
Post
Replies
Boosts
Views
Activity
With the integration of Apple's pushToTalk framework - we create the PTChannelManager using its async initializer from AppDidFinishLaunching - using an actor to ensure the PTChannelManager is only created once.
With this we have been seeing a lot of crashes for users in our analytics dashboards happening about ~2 seconds after app launch around a task-dealloc.
Here is a simplified version of our actor and Manager - where the manager just shows the init. The init of it is an async optional init because the creation of the PTChannelManager uses an async throws.
actor PushToTalkDeviceContainer {
private var internalPushToTalkManagerTask: Task<PushToTalkManager?, Never>?
func pushToTalkManager() async -> PushToTalkManager? {
#if !os(visionOS)
if let internalPushToTalkManagerTask {
return await internalPushToTalkManagerTask.value
}
let internalPushToTalkManagerTask = Task<PushToTalkManager?, Never> {
return await PushToTalkManagerImp()
}
self.internalPushToTalkManagerTask = internalPushToTalkManagerTask
return await internalPushToTalkManagerTask.value
#else
return nil
#endif
}
}
public class PushToTalkManagerImp: PushToTalkManager {
public let onPushToTalkDelegationEvent: AnyPublisher<PushToTalkDelegationEvent, Never>
public let onPushToTalkAudioSessionChange: AnyPublisher<PushToTalkManagerAudioSessionChange, Never>
public let onChannelRestoration: AnyPublisher<UUID, Never>
private let ptChannelManager: PTChannelManager
private let restorationDelegate: PushToTalkRestorationDelegate
private let delegate: PushToTalkDelegate
init?() async {
self.delegate = PushToTalkDelegate()
self.restorationDelegate = PushToTalkRestorationDelegate()
self.onPushToTalkDelegationEvent = delegate.pushToTalkDelegationSubject.eraseToAnyPublisher()
self.onPushToTalkAudioSessionChange = delegate.audioSessionSubject.eraseToAnyPublisher()
self.onChannelRestoration = restorationDelegate.restorationDelegateSubject.eraseToAnyPublisher()
do {
ptChannelManager = try await PTChannelManager.channelManager(delegate: delegate, restorationDelegate: restorationDelegate)
} catch {
return nil
}
}
}
The crash stack trace is as follows:
0 libsystem_kernel.dylib 0x00000001e903342c __pthread_kill + 8 (:-1)
1 libsystem_pthread.dylib 0x00000001fcdd2c0c pthread_kill + 268 (pthread.c:1721)
2 libsystem_c.dylib 0x00000001a7ed6c34 __abort + 136 (abort.c:159)
3 libsystem_c.dylib 0x00000001a7ed6bac abort + 192 (abort.c:126)
4 libswift_Concurrency.dylib 0x00000001ab2bf7c8 swift::swift_Concurrency_fatalErrorv(unsigned int, char const*, char*) + 32 (Error.cpp:25)
5 libswift_Concurrency.dylib 0x00000001ab2bf7e8 swift::swift_Concurrency_fatalError(unsigned int, char const*, ...) + 32 (Error.cpp:35)
6 libswift_Concurrency.dylib 0x00000001ab2c39a8 swift_task_dealloc + 128 (TaskAlloc.cpp:59)
7 MyApp 0x0000000104908e04 PushToTalkManagerImp.__allocating_init() + 40 (PushToTalkManager.swift:0)
8 MyApp 0x0000000104908e04 closure #1 in PushToTalkDeviceContainer.pushToTalkManager() + 60
9 MyApp 0x00000001041882e9 specialized thunk for @escaping @callee_guaranteed @Sendable @async () -> (@out A) + 1 (<compiler-generated>:0)
10 MyApp 0x0000000103a652bd partial apply for specialized thunk for @escaping @callee_guaranteed @Sendable @async () -> (@out A) + 1 (<compiler-generated>:0)
11 libswift_Concurrency.dylib 0x00000001ab2c2775 completeTaskWithClosure(swift::AsyncContext*, swift::SwiftError*) + 1 (Task.cpp:463)