I checked my app for catalyst runs well in macOS Big Sur 11 beta 7(20A5374g)!
Post
Replies
Boosts
Views
Activity
I had a same problem +1.
After few hours later, I cloud solve this question by myself.
These are difference that my screenshots claim:
・lineFragmentRect
・lineFragmentUsedRect
Please look at the right edge of red borders. These maxX and width are not equal. Assuming from this behavior, I understand that lineFragmentRect is rect for proposing line fragment in glyph layout process, and lineFragmentUsedRect is actual rect that the glyphs are filled, considering word wrap and hyphen factor.
・Code I used for investigation.
func addLineFragmentBorder(of text: String) {
let range = (textView.text as NSString).range(of: text)
let glyphRange = textView.layoutManager.glyphRange(forCharacterRange: range, actualCharacterRange: nil)
// You can try the difference by changing `lineFragmentUsedRect` to `lineFragmentRect`.
let lineRect = textView.layoutManager.lineFragmentUsedRect(forGlyphAt: glyphRange.location, effectiveRange: nil)
let borderLayer = CALayer()
borderLayer.frame = .init(x: lineRect.minX, y: lineRect.minY + textView.textContainerInset.top, width: lineRect.width, height: lineRect.height)
borderLayer.borderColor = UIColor.red.cgColor
borderLayer.borderWidth = 2
borderLayer.backgroundColor = UIColor.clear.cgColor
textView.layer.addSublayer(borderLayer)
}
PS:
I've updated my understanding. lineFragmentRect is rect that a layoutManager proposes lineFragment which the width as big as possible considering exclusionPaths. lineFragmentUsedRect is rect that the glyphs actually use.
Fortunately, I found a solution! A @MainActor static func showManageSubscriptions(in scene: UIWindowScene) async throws suspends the task until the user selects "Done" or "Cancel" in the manage subscription screen, so you can manually check the updated state in the next line.
Task {
do {
// The method suspends the execution until the user selects "Done" or "Cancel"
try await AppStore.showManageSubscriptions(in: view.window!.windowScene!)
// The line is executed after dismissing the screen. You can check the latest state of your app's subscription, then update your UI.
await checkAndUpdateAppSubscriptionStateI()
} catch let storeKitEerror as StoreKitError {
// Error handling
}
}
Good news for you! Today, iPadOS with catalyst automatically translates navigationItem.searchController to AppKit native NSSearchToolbarItem. (However, only automatic-translation support AppKit native component. It is not available with manual NSToolbar.
Please check the wwdc session. https://developer.apple.com/videos/play/wwdc2022/10076/
A public sample project is here https://developer.apple.com/documentation/uikit/app_and_environment/supporting_desktop-class_features_in_your_ipad_app.
I've got same issue
I had experienced same problem. I guess the problem is rooted on an AppExtension target. I solved the problem by moving the file contains a concrete AppShortcutsProvider type to my host app target.
My Workaround
func bottomBarAlternative<V>(@ViewBuilder _ content: () -> V) -> some View where V : View {
self.safeAreaInset(edge: .bottom) {
HStack {
content()
}
.labelStyle(.iconOnly)
.imageScale(.large)
.padding()
.frame(maxHeight: 50)
.background(Material.ultraThinMaterial)
.overlay {
VStack(spacing: 0) {
Divider()
Spacer()
}
}
.accessibilityElement(children: .contain)
.accessibilityLabel("Toolbar")
}
}
In addition to my testing that 20~30 seconds are given to perform(), I've found an apple official comment about how much perform()method is given in Responding to the Action button on Apple Watch Ultra
Then, implement your intent’s perform() method. The system calls this method when anything triggers the intent. In your implementation, you have 30 seconds to start a workout session and return a successful value. If you don’t start a workout session in that time, the system displays an error message, but the app remains in the foreground. People can start a workout session directly from the app, but without a session, the app goes to the background the next time they drop their wrist
In the documentation, Apple says workout intent's perform() has 30 seconds.
I have experienced the problem too, in my iOS 17.5.1 physical device.
My predicate is metadataQuery.predicate = NSPredicate(format: "%K LIKE %@", NSMetadataItemFSNameKey, "*.json").
What Xcode says:
"[ERROR] couldn't fetch remote operation IDs: NSError: Cocoa 257"
"Error returned from daemon: Error Domain=com.apple.accounts Code=7 "(null)""
@Onymacris, I could solve the problem! Error messages are still shown, but I guess that the query and error messages are separate, and not related problem.
I've moved calling my startQuery method from RootView.task to RootView.onAppear.
struct MyApp : App {
var body: some Scene {
WindowGroup {
RootView()
.onAppear { startQuery() }
}
}
}
This works fine! Only delaying the call may solve the query problem.
In Apple official sample, it starts query at viewDidLoad(). It is not so fast timing.
I have reported the issue to Feedback Report (FB14067691).
For people who want to show an alert as soon as possible after the FamilyActivityPicker has crashed, I'll share my workaround !
Workaround
struct MyView : View {
let stateUpdateTimer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State private var updateFlag: Bool = false
var body : some View {
ZStack {
Text(verbatim: "A") // This should not be empty.
.foregroundStyle(.clear)
.accessibilityHidden(true)
.opacity(updateFlag ? 1 : 0)
ContentUnavailableView(...)
FamilyActivityPicker(...)
}
.onReceive(stateUpdateTimer) { _ in
updateFlag.toggle()
}
}
}
Description
At first glance, it looks like the FamilyActivityPicker has frozen, but I realized that it simply doesn’t redraw. Therefore, if there is an event that triggers a redraw, it will quickly transition to a transparent after the crash.
The above code forces a view update every second by toggling the opacity of a view that is completely irrelevant to the user.
This let the FamilyActivityPicker transition to a transparent and immediately show an alert in ZStack.
Good Points
This workaround doesn't touch any private API and private class. It relies only on public APIs and minimal code, therefore It will continue to work without issues even if the internal implementation is changed in the future.