Post

Replies

Boosts

Views

Activity

Error about Siri capability exporting Catalyst app as Developer ID
I'm working on enabling Catalyst for my existing iOS app. When I try to archive and export Catalyst as a Developer ID-signed Mac app, I get the following error: Cannot create a Mac Catalyst Developer ID provisioning profile for "[my bundle ID]". The Siri capability is not available for Mac Catalyst Developer ID provisioning profiles. Disable this feature and try again. My iOS app uses SiriKit to donate a Siri intent, so Siri is among the capabilities listed in the Signing and Capabilities tab in the project inspector in Xcode. I don't see a way to turn that capability off only for Catalyst (like you can link some frameworks only for Catalyst or iOS), and I don't want to disable Siri entirely in my iOS app. What's going on here? What do I need to do to "disable this feature" for Catalyst?
2
0
1.3k
Jun ’21
How do I implement drop operation in UICollectionView drag and drop with an async data source and cell registration?
I have a UICollectionView tied to a UICollectionViewDiffableDataSource, and I'm generating and applying snapshots to the datasource on a background serial queue, and generating cells using UICollectionViewCellRegistration. I'm working on supporting reordering of the contents of the collection view via drag and drop, and I'm having trouble with what to do in collectionView:performDropWithCoordinator: so the reorder animation looks right. Normally, I would do something like this: -(void)collectionView:(UICollectionView *)collectionView performDropWithCoordinator:(id<UICollectionViewDropCoordinator>)coordinator { NSIndexPath *sourcePath = (NSIndexPath *)coordinator.items.firstObject.dragItem.localObject; NSInteger fromIndex = sourcePath.item; NSInteger toIndex = coordinator.destinationIndexPath.item; NSNumber *fromItem = [self.datasource itemIdentifierForIndexPath:sourcePath]; NSNumber *toItem = [self.datasource itemIdentifierForIndexPath:coordinator.destinationIndexPath]; //Do the move in the data model [MyModel moveItemFrom:fromIndex to:toIndex]; //Do the move in the datasource. This is the data source equivalent of: //[collectionView moveItemAtIndexPath:sourcePath toIndexPath:coordinator.destinationIndexPath]; NSDiffableDataSourceSnapshot *snap = self.datasource.snapshot; if (toIndex < fromIndex) [snap moveItemWithIdentifier:fromItem beforeItemWithIdentifier:toItem]; else [snap moveItemWithIdentifier:fromItem afterItemWithIdentifier:toItem]; [self.dataSource applySnapshot:snap animated:YES]; //Drop the item [coordinator dropItem:coordinator.items.firstObject.dragItem toItemAtIndexPath:coordinator.destinationIndexPath]; } But because my datasource updates happen on a background queue, I have to do at least the snapshot generation and application asynchronously, and I'd like to do the actual data model modification there too to avoid hangs. And I need to call dropItem on the coordinator on the main queue in this method. This results in an odd animation where the dropped item momentarily disappears (when drop is called) and then reappears (when the data source is updated on the background queue). The best idea I have so far is to use UICollectionViewDropPlaceholder to hold the place in the collection view until the data source is updated. But to create a placeholder I need a cell reuse identifier (docs on init method), and I don't have one of those because I'm creating my cells using cell registrations. So my question: what do I do in the performDrop method to make this work correctly? If the placeholder is the right idea, how do I use it in this situation?
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
1k
Nov ’21
How do I support the fast-scrolling scrubber using UICollectionViewDiffableDataSource?
I have a UICollectionView that I feed data into using UICollectionViewDiffableDataSource. I want to display a scroll scrubber on the trailing edge of it, like I'd get if I implemented the data source methods indexTitlesForCollectionView and indexPathForIndexTitle. But the data source is the diffable data source object, and there's no property or closure on it to supply index titles as of iOS 15. How are index titles supposed to work with UICollectionViewDiffableDataSource?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
610
Nov ’21
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
987
Apr ’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
1.8k
May ’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
2
0
1k
May ’24
How to migrate macOS keychain entry to new rewritten app?
I'm working on replacing an AppKit-based Mac app with one built on Catalyst, and the Catalyst app doesn't seem to be able to read the keychain item that was saved by the old app. Both apps are using the same bundle ID. The old app uses the old SecKeychain APIs - SecKeychainFindGenericPassword and friends - and the Catalyst app uses the newer SecItemCopyMatching and such. When I try using the new API in the old app to search for the entry, it works, but the exact same code in Catalyst fails. Here's how I save an item in the old app: NSString *strItemId = @"my_item_id; NSString *username = @"user"; const char *userPointer = [username UTF8String]; NSString *password = @"password"; const char *pwPointer = [password UTF8String]; SecKeychainItemRef ref = NULL; OSStatus status = SecKeychainFindGenericPassword(0, (UInt32)strlen(strItemId.UTF8String), strItemId.UTF8String, 0, NULL, NULL, NULL, &ref); if (status == errSecSuccess && ref != NULL) { //update existing item SecKeychainAttribute attr; attr.length = (UInt32)strlen(userPointer); attr.data = (void *)userPointer; attr.tag = kSecAccountItemAttr; SecKeychainAttributeList list; list.count = 1; list.attr = &attr; OSStatus writeStatus = SecKeychainItemModifyAttributesAndData(ref, &list, (UInt32)strlen(pwPointer), pwPointer); } else { status = SecKeychainAddGenericPassword(NULL, (UInt32)strlen(strItemId.UTF8String), strItemId.UTF8String, (UInt32)strlen(userPointer), userPointer, (UInt32)strlen(pwPointer), pwPointer, NULL); } And here's the query code that works in the old app but returns errSecItemNotFound in Catalyst: NSMutableDictionary *queryDict = [[[NSMutableDictionary alloc]init]autorelease]; [queryDict setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass]; [queryDict setObject:(@"my_item_id") forKey:(__bridge id)kSecAttrService]; [queryDict setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; [queryDict setObject:(__bridge id)kCFBooleanTrue forKey:(__bridge id)kSecReturnAttributes]; CFMutableDictionaryRef outDictionary = nil; OSStatus err = SecItemCopyMatching((__bridge CFDictionaryRef)queryDict, (CFTypeRef *)&outDictionary); I tried creating a new blank AppKit-based Mac app project in Xcode and gave it the old Mac app's bundle ID, and the SecItemCopyMatching query code above works there. Then I created a new iOS target with Catalyst enabled, also with the same bundle ID, and the query code running there under Catalyst returned errSecItemNotFound. So maybe the issue is something specific to Catalyst? Is there something I need to do with the Catalyst app to give it access to the old app's keychain entry, besides setting its bundle ID to match the old app?
1
0
756
Oct ’24
How do I make a toolbar-style window ornament from UIKit?
I've got a UIKit app and I want to add some buttons in a top-edge window ornament. I'm looking at the WWDC23 talk Meet UIKit for Spatial Computing, and it does exactly what I think I want to do: extension EditorViewController { func showEditingControlsOrnament() { let ornament = UIHostingOrnament(sceneAlignment: .bottom, contentAlignment: .center) { EditingControlsView(model: controlsViewModel) .glassBackgroundEffect() } self.ornaments = [ornament] editorView.style = .edgeToEdge } } But the thing I really want to know is what is in EditingControlsView. Is it a toolbar? How do you make a toolbar in SwiftUI without something to attach the .toolbar modifier to?
1
0
388
Oct ’24
How can I get a tab-bar styled ornament on the trailing edge of a view controller?
I've got a UIKit app with a collapsible trailing-edge child view controller, implemented sort of like UISplitViewController but it's got a bunch of custom behavior - moving to the bottom edge in portrait orientation, etc. It exposes a couple of different app functions via a UITabBar on the bottom edge on iOS. When I run the app on visionOS, that tab bar transforms to a leading-edge ornament. This would be great, but that means it tries to overlap the trailing-edge content of its parent view controller, which isn't ideal. Is there a way to get the tab bar to lay out on the trailling edge of the child view controller? Or can I create a custom ornament that has the same auto-expand behavior as the tab bar, where it shows a vertical column of icons that expands to show titles when you're gazing at it?
1
0
484
Oct ’24
InferenceError referencing context length in FoundationModels framework
I'm experimenting with downloading an audio file of spoken content, using the Speech framework to transcribe it, then using FoundationModels to clean up the formatting to add paragraph breaks and such. I have this code to do that cleanup: private func cleanupText(_ text: String) async throws -> String? { print("Cleaning up text of length \(text.count)...") let session = LanguageModelSession(instructions: "The content you read is a transcription of a speech. Separate it into paragraphs by adding newlines. Do not modify the content - only add newlines.") let response = try await session.respond(to: .init(text), generating: String.self) return response.content } The content length is about 29,000 characters. And I get this error: InferenceError::inferenceFailed::Failed to run inference: Context length of 4096 was exceeded during singleExtend.. Is 4096 a reference to a max input length? Or is this a bug? This is running on an M1 iPad Air, with iPadOS 26 Seed 1.
5
0
354
Jul ’25
How do I handle Ask to Buy or retried purchases with Price Tiers?
I work on an e-reader app that sells books as IAPs. We have a lot - about 20,000 or so. This is over Apple's limit of 10,000 IAPs, so we've had to ask them to raise the limit for us more than once. Recently, at Apple's suggestion, we finally switched to a mechanism called Price Tiers, where instead of having one IAP item in App Store Connect for each of our products, we have one item per price level, so if the user buys product ID (in our system) 12345 for $5, instead of buying non-consumable IAP ID com.mycompany.myapp.12345, they buy consumable IAP ID com.mycompany.myapp.price_tier.5. In our system, we link the purchase to product 12345 at the time of receipt verification and everything works great. But I have an issue that manifests when the user is using Ask to Buy or when receipt validation fails in our back-end, I don't call finishTransaction, and the transaction is retried later. The sequence is this: User buys product 12345, which is com.mycompany.myapp.price_tier.5 The user has Ask to Buy enabled, so the transaction ends in the deferred state, and the IAP flow on the device is done for now At some point later, the user gets permission for the purchase, and my SKPaymentQueue delegate gets notified of the transaction again in the background But at the point of step 3, I have no way of knowing what product in our system the transaction is for. The same issue occurs if receipt verification fails on our end - I don't call finishTransaction, so StoreKit retries it later, but again at that point I don't know which one of our products to register to the user's account. How do I make Ask to Buy (or any situation where I get notified of a transaction outside of a user-driven purchase) work with Price Tiers?
0
0
771
Nov ’21
How can I choose what scene gets opened on iPad after all are closed?
I have an iPad app in which I'm starting to support multiple windows / scenes. I have one main window type, let's say MainScene, and at least one secondary window type for opening specific types of content, say DetailScene. I have not declared my scene types in Info.plist. I have implemented application:configurationForConnectingSceneSession:options: like this: -(UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options { NSUserActivity *activity = options.userActivities.anyObject; NSString *activityType = activity.activityType; if ([activityType isEqualToString:@"detailType"]) return [DetailSceneDelegate makeSceneConfiguration]; return [MainSceneDelegate makeSceneConfiguration]; } Say I perform these steps: Launch app for the first time. I get a call to configurationForConnectingSceneSession, and the activity type is nil so it returns a MainScene. Open a new window for some piece of content. That uses the detail scene activity type, so configurationForConnectingSceneSession returns a DetailScene. Creating the new scene looks like this: NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:@"detailType"]; activity.userInfo = @{@"content_id": @(contentRowId)}; [[UIApplication sharedApplication] requestSceneSessionActivation:nil userActivity:activity options:nil errorHandler:nil]; Suspend the app and open the app switcher. Discard (by flicking up) first the main window and then the detail window. The app is now killed. Relaunch the app. At this point I do not get a call to configurationForConnectingSceneSession. I get the detail scene back, restored from its user activity, with calls straight to DetailSceneDelegate. My question: how do I control what scene gets restored in this situation? I want my main scene to come back. Messages and Mail and Notes all do this. If you open Messages and drag a conversation out into a new window, you get a window for that conversation with a Done button in the corner that will dismiss the window. If you perform my steps above with Messages, you will relaunch to the full Messages view. Are they converting the detail view to a main view on the fly? Or is there a way to tell the system that the detail scene is secondary and should not be restored first, or that I should get asked what I want to restore via configurationForConnectingSceneSession? Or something else?
2
0
1.4k
Mar ’22
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?
4
0
1.7k
Dec ’24
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.
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
716
Jun ’23