Posts

Post not yet marked as solved
16 Replies
4.3k Views
I'm working on a tvOS app using the new UICollectionViewDiffableDataSource to display up to 4 sections of groups of movies. If I'm scrolling the collectionView one poster at a time it works fine, but if I perform a quick swipe up or down between the sections, when we reach the top or bottom most cell a duplicate cell is made and 2 cells display in the same space overlapping each other. Here is the code I'm using to create the cells: if let collectionView = self.collectionView { self.dataSource = UICollectionViewDiffableDataSource.init(collectionView: collectionView, cellProvider: { (collectionView, indexPath, entity) -> UICollectionViewCell? in if let cell: PosterCollectionViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: self.cellIdentifier, for: indexPath) as? PosterCollectionViewCell { print("Creating cell \(cell) for content named \(entity.title ?? "") index path \(indexPath) on Thread \(String(describing: Thread.current))") cell.populate(withEntity: entity) return cell } return UICollectionViewCell() }) }Here are a few screen shots of what it looks like visually when the duplicate cells are created:I noticed on the print logs, whenever I scroll through the collectionView and the cell goes offscreen and gets recreated - it resuses the cell previously created each time (7 times in this case) EXCEPT when I perform the quick swipe. In that case, the same cell gets dequeued and then another immediately gets created with a new memory address. I assumed the closure on the UICollectionViewDiffableDataSource init method was being called on the main thread, but did a printout of the thread the cells were being created on just incase (and they obviously were), so I'm not sure why even if a new cell was being created it would duplicate the cell and overlay it instead of replacing it.Creating cell PosterCollectionViewCell: 0x7fbc94011220; baseClass = UICollectionViewCell; frame = (10 1237; 248.5 330); opaque = NO; layer = CALayer: 0x600003d7cfe0 for content named Joker index path [3, 0] on Thread NSThread: 0x6000028ccbc0{number = 1, name = main} Creating cell PosterCollectionViewCell: 0x7fbc91e1d7d0; baseClass = UICollectionViewCell; frame = (10 1218; 248.5 330); opaque = NO; layer = CALayer: 0x600003d95b20 for content named Joker index path [3, 0] on Thread NSThread: 0x6000028ccbc0{number = 1, name = main}This only happens when I perform the quick swipe and land on a poster that is the top or bottom most on a section I can navigate to. It won't stop at just 2 either. If I continue the behavior, yet another cell gets created, you can see here in the view debugger we have 3 cells for the Joker movie in a section that should just be displaying the one cell:Also, note that I am using the new UICollectionViewCompositionalLayout and am setting it up with this methodstatic func createLayout(posterHeight height: CGFloat, postersOnScreen numPosters: CGFloat, headerHeight: CGFloat = 0, edgeInsets: NSDirectionalEdgeInsets? = nil) -> UICollectionViewCompositionalLayout { let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0 / numPosters), heightDimension: .fractionalHeight(1.0)) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(height)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.orthogonalScrollingBehavior = .continuous if let edgeInsets = edgeInsets { section.contentInsets = edgeInsets } if headerHeight > 0 { let headerFooterSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .estimated(headerHeight)) let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem( layoutSize: headerFooterSize, elementKind: UICollectionView.elementKindSectionHeader, alignment: .top) section.boundarySupplementaryItems = [sectionHeader] } return UICollectionViewCompositionalLayout(section: section) }The cell duplication also seems to only happen when scrolling to a cell that was previously offscreen. When the cell comes on screen it performs the standard animation when it becomes focused and the duplicate is created.
Posted Last updated
.
Post not yet marked as solved
0 Replies
671 Views
I'm working on implementing spatial audio on our tvOS app and I connected my 4K AppleTV to my AirPod Pro headphones for testing. I'm seeing an issue where during playback of a movie there is no audio during playback until I seek to a new position and then the audio is fine. Even if I back out and play a new content the audio still works, but ONLY after I skip back/forward 15 seconds, or click in the remote and seek to a new playback position. This issue doesn't exist when connected to a HomePod or through the TV speakers, only when I'm connected via AirPods. Also it is not only occurring when playback is initiated with the AirPod Pros connected. If I start off connected to audio through my HomePod the audio is fine, then I use PiP and in the Settings app switch to AirPods from the temporary audio screen and the audio goes out, switch back to HomePod and the audio returns. Anyone else run into this issue/have any suggestions? Also this is happening on my dev build, the app we have in the AppStore built from Xcode 12.4 does not have this issue. Edit: Noting that this is only happening on XCode 13 running to a device that has the tvOS 15 Beta.
Posted Last updated
.
Post not yet marked as solved
1 Replies
649 Views
I'm currently attempting to move some code from my project into a Swift Package. Some of the code is in Swift and some in ObjC, both contain some UIViewControllers that have corresponding storyboards to lay them out. I've gotten it almost all worked out except for the Storyboard references from my Swift target, which are pointing to a storyboard in my ObjC target. I haven't seen any examples that show how to achieve this, any help would be appreciated.
Posted Last updated
.
Post marked as solved
3 Replies
1.3k Views
I'm currently developing a tvOS app and when I reach the sign in flow I can select from a list of Previously-used email addresses in order to sign in. Now the email address I want to use is not listed, so I must manually type it in. But even after logging in, if I log out and go to the same list, the email address previously used is not listed. I know through Settings -> General -> Previously-Used Emails I can remove an email address, but is there any way I can programatically add the email address the user entered to the list?
Posted Last updated
.
Post not yet marked as solved
0 Replies
733 Views
Hey all, I'm working on enabling multitasking for iPad and when I made a few adjustments to my LaunchScreen_iPad.storyboard file (which is also defined in the Info.plist under UILaunchStoryboardName~ipad), when I launch the app in Regular|Regular size class, the app is launched with a cached version of my storyboard and the updated constraints on the imageview are not applied. I even tried renaming the storyboard to LaunchScreenV2_iPad and the constraints still are not updated. I then deleted the image view altogether and when I launch the app in Regular | Regular size class, the cached version still displays. Has anyone else run into this issue?
Posted Last updated
.
Post not yet marked as solved
0 Replies
671 Views
I'm trying to update our app to stop using the deprecated methods for toggling Closed Captions on the AVPlayer. We're using the following logic to determine whether captions are currently displaying captions: if let group = self.playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: AVMediaCharacteristic.legible), let optionGroup = self.playerItem.currentMediaSelection.selectedMediaOption(in: group) { return true } return falseThen we use the inverse value of what the above method returns to toggle the captions on or off.let subtitlesGroup = self.playerItem.asset.mediaSelectionGroup(forMediaCharacteristic: .legible) // on self.playerItem.select(subtitlesGroup.options.first, in: subtitlesGroup) // off self.playerItem.select(nil, in: subtitlesGroup)When playing back on the device locally this works perfectly, but when we attempt to transition to playback over AirPlay, the first method always returns true regardless of whether or not captions are displaying. I've forced the 2nd method to switch between on/off using a local variable to ensure the commands would work, and they do, so the issue comes down to this line always returning a valid AVMediaSelectionOption while playing back via AirPlayself.playerItem.currentMediaSelection.selectedMediaOption(in: group)Anyone run into this issue? Any other value I should be checking instead when playing back via AirPlay?
Posted Last updated
.
Post not yet marked as solved
0 Replies
807 Views
We have a situation where downloaded HLS content can stall, most frequently on first playback. The concrete steps I can use to replicate this issue are:- Downloads HLS content- Force kill the app- Relaunch the app- Play the downloaded contentIf we get a Notification when listening for Notification.Name.AVPlayerItemNewErrorLogEntry we get the following error<AVPlayerItemErrorLog: 0x281b13bb0>#Version: 1.0#Software: AppleCoreMedia/1.0.0.16D57 (iPhone; U; CPU OS 12_1_4 like Mac OS X; en_us)#Date: 2019/07/11 15:54:15.015#Fields: date time uri cs-guid s-ip status domain comment cs-iftype2019/07/11 15:54:15.015 (License server URI) B9ECC2F4-4D52-4178-8E72-546AC90CDCC4 - -12885 "CoreMediaErrorDomain" - unknownThe odd part is if we check that we are playing downloaded content and that the AVPlayer status is == .readyToPlay, calling play() on the player will get playback to start 80% of the time. The other 20% (and 100% reproducible using the above ^ steps listed) will cause our observer on the timeControlStatus property to fire with the value == .waitingToPlayAtSpecifiedRate, at that point the player's .reasonForWaitingToPlay property == AVPlayer.WaitingReason.toMinimizeStalls, and the player's currentItem's property .isPlaybackBufferEmpty == true. Once in this state, the only way to get playback to start is to seek forward 1 second (or if the user uses the UISlider to seek to a new position within the content). If the user kills the app and relaunches, the player will remain in this "buffering" state. Or if we call play(), or pause() then play() on the player, (either in code or though the user tapping the play button) playback will never start. Backing out of the player and immediately restarting the content also fixes the issue, but that's a horrible user experience. Also, using a manual seek will correct this issue and stop it from happening again if the app is dismissed and relaunched.Any advice on how to get out of this state without seeking? Or info about how or why the AVPlayer would be in this state when the content is downloaded and readily available on disk?
Posted Last updated
.