Post

Replies

Boosts

Views

Activity

How can I make NSToolbar on Catalyst check canPerformAction on UISplitViewController's secondary view controller instead of primary?
I have a Catalyst app that I'm adding a sidebar to via UISplitViewController. I have a toolbar on the window with buttons that I want to be enabled or disabled based on the state of the view controller in the split view's secondary column. But it seems to want to check the primary view controller instead. In the Catalyst tutorial Adding a Toolbar, this exact approach is demonstrated. The RecipeDetailViewController has methods for toggleFavorite and editRecipe, and the toolbar items are set up to reference those selectors in the ToolbarDelegate class. In the screenshots in the tutorial, the buttons are shown as enabled based on RecipeDetailViewController.canPerformAction. But when I download and run the complete project on my computer (macOS 14.4.1), the toolbar items are disabled. And if I add the methods to the RecipeListViewController (which is in the primary column of the UISplitViewController, the toolbar items get enabled. Is there a way to make the system ask the correct split view column for canPerformAction? Or is this a bug?
0
0
163
4w
How can I put an NSToolbarItem on the leading edge of an NSToolbar in Catalyst?
I'm working to make my iOS app available via Catalyst, and I'm adding a leading-edge sidebar via UISplitViewController and putting a toggle button in the window toolbar to control it. I'd like that sidebar toggle button to go on the leading side of the toolbar, before the window title. In the Adding a Toolbar Catalyst tutorial, there are screenshots of this behavior: But when I download the finished project and run it on my machine (macOS 14.4), the toolbar buttons are clustered on the trailing edge: How do I achieve the behavior shown in the tutorial's screenshot, where the toggle sidebar button (or, ideally any custom toolbar item I choose) shows up on the leading edge? Even more ideally, is there a way I can make the sidebar toggle button show up in the header section for the sidebar, like it does in Xcode - right next to the stoplight buttons?
1
0
178
Apr ’24
How do I open my app's section of Notification settings in Catalyst?
I have a button in my iOS app that opens the Settings app to my app's Notification permissions section. I use UIApplicationOpenSettingsURLString for this (or UIApplicationOpenNotificationSettingsURLString on iOS 15.4 and later). On Catalyst, both of these simply open the settings screen that is auto-generated from the Settings bundle. How do I get it to open to the appropriate place in System Settings?
1
1
424
Dec ’23
NSTextView crash with interaction between inserted .link attribute in text storage and NSSpellChecker
I have been getting crash reports from users of my Mac app on Sonoma 14.0 and 14.1 when typing into an NSTextView subclass. The crash logs I have show involvement of the spell-checking system - NSTestCheckingController, NSSpellChecker, and NSCorrectionPanel. The crash is because of an exception being thrown. The throwing method is either [NSString getParagraphStart:end:contentsEnd:forRange:] or [NSTextStorage ensureAttributesAreFixedInRange:]. I have not yet reproduced the crash. I have tried modifying the reference finding process to simply link every word, via NSStringEnumerationByWords. The text view in question recognizes certain things in the entered text and adds hyperlinks to the text while the user is typing. It re-parses and re-adds the links on every key press (via overriding the didChangeText method), on a background thread. From user reports, I have learned that: The crash only occurs on macOS 14.0 and 14.1, not on previous versions The call stack always involves the spell checker, and sometimes involves adding recognized links to the text storage (the call to DispatchQueue.main.async in the code below) The crash stops happening if the user turns off the system spell checker in System Settings -> Keyboard -> Edit on an Input Source -> Correct Spelling Automatically switch The crash does not happen when there are no links in the text view. Here is the relevant code: extension NSMutableAttributedString { func batchUpdates(_ updates: () -> ()) { self.beginEditing() updates() self.endEditing() } } class MyTextView : NSTextView { func didChangeText() { super.didChangeText() findReferences() } var parseToken: CancelationToken? = nil let parseQueue = DispatchQueue(label: "com.myapp.ref_parser") private func findReferences() { guard let storage = self.textStorage else { return } self.parseToken?.requestCancel() let token = CancelationToken() self.parseToken = token let text = storage.string self.parseQueue.async { if token.cancelRequested { return } let refs = RefParser.findReferences(inText: text, cancelationToken: token) DispatchQueue.main.async { if !token.cancelRequested { storage.batchUpdates { var linkRanges: [NSRange] = [] storage.enumerateAttribute(.link, in: NSRange(location: 0, length: storage.length)) { linkValue, linkRange, stop in if let linkUrl = linkValue as? NSURL { linkRanges.append(linkRange) } } for rng in linkRanges { storage.removeAttribute(.link, range: rng) } for r in refs { storage.addAttribute(.link, value: r.url, range: r.range) } } self.verseParseToken = nil } } } } } I've filed this as FB13306015 if any engineers see this. Can anyone
1
0
412
Oct ’23
Is AAAttribution.attributionToken safe for the main thread?
I'm seeing some hang reports for my app in the Xcode organizer that boil down to [AAAttribution attributionTokenWithError:]. The docs for that method talk a lot about a request to Apple's services, but it looks like that's about passing the fetched token up to be decoded...but is the method also making a network request? Or is it doing something else that shouldn't be done on the main thread? If it wasn't main-thread safe I'd expect it to be documented as such, or for the Swift version to be async...
0
0
534
Oct ’23
Why does NSAttributedString's NSItemProviderWriting implementation not transfer custom attributes that implement Codable?
I am working on supporting some formatted text editing in my app, and I've been experimenting with copy and paste support for formatted text. I discovered that NSAttributedString implements NSItemProviderWriting, which means I can give it to UIPasteboard via setObjects and all the built-in attributes transfer perfectly if I then paste it into another text view, or even another app that behaves itself. But if I have custom attributes in my attributed string, having their values implement Codable doesn't let them transfer across the clipboard. In my implementation of textPasteConfigurationSupporting(_: transform:), I try to get an attributed string like this: let attr = item.itemProvider.loadObject(ofClass: NSAttributedString.self) { val, err in //...handle here } I get an error like this: Error Domain=NSItemProviderErrorDomain Code=-1000 "Cannot load representation of type com.apple.uikit.attributedstring" UserInfo={NSLocalizedDescription=Cannot load representation of type com.apple.uikit.attributedstring, NSUnderlyingError=0x600003e7bea0 {Error Domain=NSCocoaErrorDomain Code=260 "The file “b036c42113e34c2f9d9af14d6fefcbd534f627d6” couldn’t be opened because there is no such file." UserInfo={NSURL=file:///Users/username/Library/Developer/CoreSimulator/Devices/86E8BDD4-B6AA-4170-B0EB-57C74EC7DDF0/data/Library/Caches/com.apple.Pasteboard/eb77e5f8f043896faf63b5041f0fbd121db984dd/b036c42113e34c2f9d9af14d6fefcbd534f627d6, NSFilePath=/Users/username/Library/Developer/CoreSimulator/Devices/86E8BDD4-B6AA-4170-B0EB-57C74EC7DDF0/data/Library/Caches/com.apple.Pasteboard/eb77e5f8f043896faf63b5041f0fbd121db984dd/b036c42113e34c2f9d9af14d6fefcbd534f627d6, NSUnderlyingError=0x600003e7ac70 {Error Domain=NSPOSIXErrorDomain Code=2 "No such file or directory"}}}} But I tried making my custom attribute values implement NSSecureCoding, and then it worked. Why is Codable conformance not enough here? Is it because the code that serializes and deserializes is still in Objective-C and isn't aware of Codable? Will this change as the open-source Foundation in Swift work continues?
0
0
507
Jul ’23
How can I control image sizing with UIButtonConfiguration?
WWDC 2021 session 10064 introduced UIButtonConfiguration, a new way to configure the visual appearance of buttons, for iOS 15. I've run into a surprising bit of behavior with its image setup: if you give it an image from an asset catalog that's bigger than the button's bounds, the image is sized too big for the button. See the attached screenshot of an example app. The upper play icon is a button set up with setImage:forState:, and it sizes the image down as expected. The lower one is set up with UIButtonConfiguration, and is constrained to the same size (both buttons have a red border), but its image is too big. How do I control the image sizing behavior here? FB12358840 if any engineers look at this and think there could be an API improvement here.
0
0
460
Jun ’23
How can I replicate CALayer.maskedCorners with UIButtonConfiguration and UIBackgroundConfiguration?
WWDC 2021 session 10064 introduced UIButtonConfiguration, a new way to configure the visual appearance of buttons, for iOS 15. I'm now in the process of switching all my button setup over to UIButtonConfiguration, and I've run into one situation where it doesn't apply: rounding specific corners of the button. CALayer has the maskedCorners property that lets you round or mask specific corners but not others. In transferring border radius, border width, and border color styling over to UIButtonConfiguration via UIBackgroundConfiguration, I don't see an equivalent UI. Am I missing something? For now, in cases when I need the maskedCorners functionality, I'm falling back to using the layer for border properties.
1
0
444
Jun ’23
How can I integrate my own text changes into UITextView's undo manager?
I have an app that uses UITextView for some text editing. I have some custom operations I can do on the text that I want to be able to undo, and I'm representing those operations in a way that plugs into NSUndoManager nicely. For example, if I have a button that appends an emoji to the text, it looks something like this: func addEmoji() { let inserting = NSAttributedString(string: "😀") self.textStorage.append(inserting) let len = inserting.length let range = NSRange(location: self.textStorage.length - len, length: len) self.undoManager?.registerUndo(withTarget: self, handler: { view in view.textStorage.deleteCharacters(in: range) } } My goal is something like this: Type some text Press the emoji button to add the emoji Trigger undo (via gesture or keyboard shortcut) and the emoji is removed Trigger undo again and the typing from step 1 is reversed If I just type and then trigger undo, the typing is reversed as you'd expect. And if I just add the emoji and trigger undo, the emoji is removed. But if I do the sequence above, step 3 works but step 4 doesn't. The emoji is removed but the typing isn't reversed. Notably, if step 3 only changes attributes of the text, like applying a strikethrough to a selection, then the full undo chain works. I can type, apply strikethrough, undo strikethrough, and undo typing. It's almost as if changing the text invalidates the undo manager's previous operations? How do I insert my own changes into UITextView's NSUndoManager without invalidating its chain of other operations?
3
0
916
May ’23
"Deadlock" (0xdead10cc) crashes on Developer Mode devices?
One of the things discussed in Understanding the exception types in a crash report is the 0xdead10cc code under EXC_CRASH (SIGKILL): 0xdead10cc (pronounced “dead lock”). The operating system terminated the app because it held on to a file lock or SQLite database lock during suspension. My app gets killed this way here and there, and it's been on my project list for some time to make the requisite changes to database connection handling to fix it. With an App Store build, as far as I know it just means the app cold-starts when launched instead of resuming, but in a TestFlight build it actually shows a crash reporter dialog. Reports of this issue from TestFlight users got more frequent with a recent update that had the effect of keeping more SQLite handles open longer, and I realized that I personally have never seen a crash reporter dialog after fast-app-switching away from a TestFlight build on my device. And I use the TF build as my daily driver, and I use my app a lot. My question is this: is it possible that the 0xdead10cc crash doesn't happen on Developer Mode devices?
1
0
979
Apr ’23
How can I automatically insert the next NSTextList list item on return in iOS 16?
I'm adding some text formatting support to an editable text view in my app, and I want to include bulleted lists. I specifically want to have the standard behavior where if you're typing a line of text in a list and press Enter, the next bullet item is automatically inserted. This appears to somewhat work out-of-the-box with NSTextList on iOS 16, unless the line you're editing is at the very end of the document. This is apparent in the sample code for WWDC 2022 session 10090 (project is here): Run that sample app and switch to the List tab Put your cursor at the end of any line except the last one and press enter. You get a new list item, as expected. Put your cursor at the end of the very last line and press Enter. You don't get a list item until you type something on that line. I've likewise found that if I have this text in a text view: Hello World\n\nList here\n If I format the text List here as a bulleted list (by creating an NSMutableParagraphStyle with its textLists property set and adding it to the attributed string for that range) and press Enter at the end of the word Here, I get a new bullet item automatically. But if I do the same thing without having that last newline after Here, the new list item is not inserted. How can I make the list auto-continuation behavior work at the end of the document?
1
0
667
Apr ’23
What is the expected behavior for "Use Selection for Find" in a text editor?
I'm enhancing some existing text editor functionality in my app, and I'm adding support for the UIStandardEditActions method useSelectionForFind. The docs on the method say: UIKit calls this method when the user selects the Use Selection For Find command from an editing menu. Your implementation should present the UI for finding textual content in your view and use the selected text for the search. For example, a view using a find interaction might call presentFindNavigator(showingReplace:) and pass the selected text as the query string. Reading this, I'd expect that selecting text and pressing Cmd-E on an attached keyboard should display the Find UI and prefill the selected text. But in a couple of Apple apps that I tried on my iPad, Pages and Notes, pressing Cmd-E doesn't actually do anything visible, even if I hold Command to show the keyboard shortcut HUD and manually tap "Use Selection for Find". If I trigger the Find UI using Cmd-F, it does prefill the selected text, which it doesn't if I select text and press Cmd-F without pressing Cmd-E first. I tried a couple of apps on my Mac, too - Xcode, TextEdit, TextMate - and they do the same thing. Pressing Cmd-E or triggering the command via the menu item does nothing visible, but when I then bring up the find UI the text is there. Or if the find UI is already visible when I press Cmd-E, the selected text is inserted there. So, what's up here? Is that suggestion in the docs just wrong / out of step with what the standard behavior is? Or are all these apps wrong?
1
0
680
Mar ’23
How do I enable UILargeContentViewerInteraction on UITabBar outside of UITabBarController?
UILargeContentViewerInteraction, added in iOS 13, works out of the box on the tab bar in a UITabBarController, and it's easy to set up on a custom view using the UILargeContentViewerItem properties on UIView. But how do I set it up on a UITabBar that's not connected to a UITabBarController? There don't appear to be any relevant properties on UITabBarItem. To try this, I made a sample app, added a tab bar, set up some items, set their largeContentSizeImage properties for good measure, ran the app, set text size to a large accessibility value, and long-pressed on the items, and I get no large content viewer. I also tried adding a UILargeContentViewerInteraction to the tab bar, and implemented the viewControllerForInteraction method in the delegate.
2
0
730
Dec ’22
Navigation bar of custom-presented navigation controller moving to app title bar in Catalyst on Ventura
I have an iOS app that I'm looking to make available as a Catalyst app. I have various view controllers that I present using custom animations and presentation styles via UIViewControllerTransitioningDelegate, UIViewControllerAnimatedTransitioning, UIPresentationController, et al. Most of the view controllers I present with my custom styles are UINavigationController instances (or subclasses thereof). And when I build and run my Catalyst app on Ventura, the titles and bar items for the navigation items of the view controllers in the navigation stack get moved to the title bar of the application, and the navigation bar doesn't appear at all in the presented view controller. Why is this happening, and how do I stop it? I've looked through the documentation for the APIs I mentioned above and tried setting various things that seemed like they could conceivably be relevant - UIPresentationController.shouldPresentInFullscreen, UIViewController.modalInPresentation, etc - and have had no luck.
1
1
1.6k
Oct ’22
Crash on load of FairPlay DRM'd audio on Catalyst
I have an iOS app that can play audio books as FairPlay DRM'd audio streams. I'm using AVContentKeySession to fetch keys and AVQueuePlayer to play. It works great on iOS, but on Catalyst (Monterey 12.3.1, M1 Max MacBook Pro) it crashes. When it happens in debug, I get a message "Too few bits left in input buffer" printed to the console, and an exception is thrown in the guts of what appears to be core media. Here's the output from [NSThread callStackSymbols] when paused on an exception breakpoint at that point: 0   ???                       0x0000000156b8cc9c 0x0 + 5749918876, 1   BRFree                    0x000000010445cf08 main + 0, 2   AudioCodecs               0x0000000157918c24 _ZL11GetPropertyPvjPjS_ + 52, 3   AudioToolboxCore          0x00000001862536a4 _ZN15ADTSAudioStream11ParseHeaderER27AudioFileStreamContinuation + 1060, 4   AudioToolboxCore          0x000000018624259c AudioFileStreamParseBytes + 412, 5   MediaToolbox              0x00000001915f7d98 FigManifoldCreateForICY + 2176, 6   MediaToolbox              0x00000001915f7718 FigManifoldCreateForICY + 512, 7   MediaToolbox              0x00000001916bbd78 FigPlayerStreamCreate + 315920, 8   MediaToolbox              0x0000000191a269a0 FigMetadataConverterCreateForQuickTimeToFromiTunes + 45888, 9   MediaToolbox              0x0000000191a4a290 FigMetadataConverterCreateForQuickTimeToFromiTunes + 191536, 10  MediaToolbox              0x0000000191a2a470 FigMetadataConverterCreateForQuickTimeToFromiTunes + 60944, 11  MediaToolbox              0x0000000191a28c34 FigMetadataConverterCreateForQuickTimeToFromiTunes + 54740, 12  MediaToolbox              0x0000000191a413b4 FigMetadataConverterCreateForQuickTimeToFromiTunes + 154964, 13  MediaToolbox              0x0000000191a2f144 FigMetadataConverterCreateForQuickTimeToFromiTunes + 80612, 14  MediaToolbox              0x00000001917cae64 FigAlternateFilterMonitorCreateForThermalNotification + 30428, 15  MediaToolbox              0x00000001917ccb44 FigAlternateFilterMonitorCreateForThermalNotification + 37820, 16  MediaToolbox              0x00000001917cb134 FigAlternateFilterMonitorCreateForThermalNotification + 31148, 17  CFNetwork                 0x0000000189937cd4 _CFHostIsDomainTopLevelForCertificatePolicy + 27728, 18  Foundation                0x0000000185ba980c __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 24, 19  Foundation                0x0000000185ba96b4 -[NSBlockOperation main] + 104, 20  Foundation                0x0000000185ba9644 __NSOPERATION_IS_INVOKING_MAIN__ + 24, 21  Foundation                0x0000000185ba88dc -[NSOperation start] + 788, 22  Foundation                0x0000000185ba85c0 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 24, 23  Foundation                0x0000000185ba8478 __NSOQSchedule_f + 184, 24  libdispatch.dylib         0x00000001099f60f4 _dispatch_block_async_invoke2 + 148, 25  libdispatch.dylib         0x00000001099e2394 _dispatch_client_callout + 20, 26  libdispatch.dylib         0x00000001099eb778 _dispatch_lane_serial_drain + 980, 27  libdispatch.dylib         0x00000001099ec814 _dispatch_lane_invoke + 492, 28  libdispatch.dylib         0x00000001099f9fc8 _dispatch_root_queue_drain + 408, 29  libdispatch.dylib         0x00000001099f9d3c _dispatch_worker_thread + 264, 30  libsystem_pthread.dylib   0x00000001094e1890 _pthread_start + 148, 31  libsystem_pthread.dylib   0x00000001094ebaa8 thread_start + 8 In the Debug Navigator, the top of the stack looks a little different: #0 0x0000000184bdeb3c in __cxa_throw () #1 0x000000015791941c in ACMP4AACLowComplexityDecoder::GetProperty(unsigned int, unsigned int&, void*) () #2 0x0000000157918c24 in GetProperty(void*, unsigned int, unsigned int*, void*) () #3 0x00000001862536a4 in ADTSAudioStream::ParseHeader(AudioFileStreamContinuation&) () #4 0x000000018624259c in AudioFileStreamParseBytes () #5 0x00000001915f7d98 in ___lldb_unnamed_symbol598$$MediaToolbox () What's going wrong here? Can anyone give me direction on what to fix? Or is FairPlay audio not even expected to work in Catalyst at this point?
2
1
731
Apr ’22