Post

Replies

Boosts

Views

Activity

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.5k
Mar ’22
How can I use UICollectionViewDiffableDataSource reorderHandlers with a custom compositional layout?
As of iOS 14, UICollectionViewDiffableDataSource has a reorderHandlers property. It's demonstrated in some sample code and talked about in WWDC 2020 session on Advances in Diffable Data Sources. The presenter states that you have to provide a canReorder and didReorder closure to enable the feature. The sample code uses it in a collection view with a list layout configuration, and configures the list cells with reorder accessories. The canReorder and didReorder methods are called as expected. But if I remove the reorder accessories from the cells, reordering no longer works - it doesn't call either closure. It also doesn't work in my app, where I have a grid layout using a compositional layout. How do I enable reordering on UICollectionViewDiffableDataSource without list cells and reorder accessories?
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
681
Dec ’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
648
Nov ’21
Is the text color of UICollectionView index views modifiable?
I notice in iOS 14 beta 4, collection views show index views on their trailing edge if the data source implements indexTitlesForCollectionView - https://developer.apple.com/documentation/uikit/uicollectionviewdatasource/2851455-indextitlesforcollectionview?language=objc and indexPathForIndexTitle - https://developer.apple.com/documentation/uikit/uicollectionviewdatasource/2851456-collectionview?language=objc. But I don't see a way to control any aspect of its appearance. On UITableView this shows up as the sectionIndexColor - https://developer.apple.com/documentation/uikit/uitableview/1614915-sectionindexcolor?language=objc property. Does this property exist on UICollectionView somewhere I didn't think to look? Or is it just not there (yet)? FB8284500
Topic: UI Frameworks SubTopic: UIKit Tags:
3
0
1.3k
Nov ’21
How can I tell if a StoreKit 2 purchase was completed on _this_ device?
In the session on StoreKit 2 (which looks amazing!), the presenter says: In fact, if your app is running when a purchase is made on another device, you'll be notified about the new transaction. This seems to mean that when an app uses the listener API to be notified of transactions, it will get transactions that happened on other devices. My app offers purchases across other platforms in addition to iOS, and when a purchase happens we register it with our own account system. If a user has the app running on both their iPad and iPhone and makes a purchase on the phone, if the iPad gets notified of it the same way it would of a purchase made on the iPad, both devices will try to report it to our system. This seems undesirable. What's the recommended approach here? Should we just make sure our system will disregard duplicate transaction reports? Or is there a way to know whether a transaction originated on this device? I don't see a property on the transaction type that looks like it could accomplish this. Maybe the deviceVerification properties? But that's seems more like the new edition of transaction receipt verification - failing that check would presumably mean that the purchase is invalid, not that it didn't happen on this device...?
2
0
3.2k
Nov ’21
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
801
Nov ’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
1.1k
Nov ’21
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 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?
Replies
2
Boosts
0
Views
1.5k
Activity
Mar ’22
How can I use UICollectionViewDiffableDataSource reorderHandlers with a custom compositional layout?
As of iOS 14, UICollectionViewDiffableDataSource has a reorderHandlers property. It's demonstrated in some sample code and talked about in WWDC 2020 session on Advances in Diffable Data Sources. The presenter states that you have to provide a canReorder and didReorder closure to enable the feature. The sample code uses it in a collection view with a list layout configuration, and configures the list cells with reorder accessories. The canReorder and didReorder methods are called as expected. But if I remove the reorder accessories from the cells, reordering no longer works - it doesn't call either closure. It also doesn't work in my app, where I have a grid layout using a compositional layout. How do I enable reordering on UICollectionViewDiffableDataSource without list cells and reorder accessories?
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
2
Boosts
0
Views
681
Activity
Dec ’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:
Replies
1
Boosts
0
Views
648
Activity
Nov ’21
Is the text color of UICollectionView index views modifiable?
I notice in iOS 14 beta 4, collection views show index views on their trailing edge if the data source implements indexTitlesForCollectionView - https://developer.apple.com/documentation/uikit/uicollectionviewdatasource/2851455-indextitlesforcollectionview?language=objc and indexPathForIndexTitle - https://developer.apple.com/documentation/uikit/uicollectionviewdatasource/2851456-collectionview?language=objc. But I don't see a way to control any aspect of its appearance. On UITableView this shows up as the sectionIndexColor - https://developer.apple.com/documentation/uikit/uitableview/1614915-sectionindexcolor?language=objc property. Does this property exist on UICollectionView somewhere I didn't think to look? Or is it just not there (yet)? FB8284500
Topic: UI Frameworks SubTopic: UIKit Tags:
Replies
3
Boosts
0
Views
1.3k
Activity
Nov ’21
How can I tell if a StoreKit 2 purchase was completed on _this_ device?
In the session on StoreKit 2 (which looks amazing!), the presenter says: In fact, if your app is running when a purchase is made on another device, you'll be notified about the new transaction. This seems to mean that when an app uses the listener API to be notified of transactions, it will get transactions that happened on other devices. My app offers purchases across other platforms in addition to iOS, and when a purchase happens we register it with our own account system. If a user has the app running on both their iPad and iPhone and makes a purchase on the phone, if the iPad gets notified of it the same way it would of a purchase made on the iPad, both devices will try to report it to our system. This seems undesirable. What's the recommended approach here? Should we just make sure our system will disregard duplicate transaction reports? Or is there a way to know whether a transaction originated on this device? I don't see a property on the transaction type that looks like it could accomplish this. Maybe the deviceVerification properties? But that's seems more like the new edition of transaction receipt verification - failing that check would presumably mean that the purchase is invalid, not that it didn't happen on this device...?
Replies
2
Boosts
0
Views
3.2k
Activity
Nov ’21
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?
Replies
0
Boosts
0
Views
801
Activity
Nov ’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:
Replies
2
Boosts
0
Views
1.1k
Activity
Nov ’21
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?
Replies
2
Boosts
0
Views
1.3k
Activity
Jun ’21