Hi.
Since Xcode 16 and/or iOS 18.0 (I upgraded at the same time), I have an strange effect in the lower (let's say) 20% section of the Navigation Bar when changing to another tab, and this independently if large titles are used or not. Mentioned section is brighter or darker than the rest of the Navigation Bar background, depending on which background tint is used. This effect lasts about 0.3 seconds, but is clearly visible, quite disturbing and new as of Xcode 16 and/or iOS 18.0.
I use the code below in AppDelegate to get a gradient coloured Navigation Bar background.
let appearance = UINavigationBarAppearance()
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
UINavigationBar.appearance().compactScrollEdgeAppearance = appearance
If I don't use above code., the background color is filled and without gradient. Subject effect doesn't show in this case.
The effect basically looks like when changing tab, the new Navigation Bar background doesn't clear right away, and keeps the background from the previous Navigation Bar for 0.3 seconds before new one Navigation Bar background is rendered.
I spent quite some time on changing every possible setting, in code as well as storyboard ... no success so far.
Any ideas how to disable this undesired animation?
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Post
Replies
Boosts
Views
Activity
If I put the phone flat on a table, the left and right swipe gestures is not working but up and down gestures works.
Only when I put the iPhone to some vertical degree, the left and right swipe works.
Tested on 2 iPhone 7 Plus and 2 iPhone 13.
Anyone has similar experience? If yes, why?
Running an existing Xcode project in an iPad OS 18 simulator is automatically using the newly introduced tab bar view, moved from the bottom to the top.
Unfortunately, the isEnabled property on a tar bar item is no longer honored.
In Xcode's Storyboard builder, some tab bar items are initially disabled. (can't add a screenshot here, I will try to do that after posting)
The iPad OS 17 simulator shows them correctly as disabled and any user interaction is suppressed as expected.
The iPad OS 18 simulator shows them as active and they can be selected. Also setting them to disabled inside of the UITabBarViewController doesn't work:
for item in self.tabBar.items! {
if item.tag != 99 {
item.isEnabled = false
}
}
They stay enabled and selectable.
As a workaround, I implemented the UITabBarViewControllerDelegate and overrode this method:
func tabBarController(_ tabBarController: UITabBarController, shouldSelect viewController: UIViewController) -> Bool {
if Global.shared.accessToken == nil {
if viewController is LoginViewController || viewController is SettingsViewController {
return true
} else {
return false
}
}
return true
}
The user can no longer select the tabs, however, there is no visual indicator that they are not selectable.
I cannot find any indication in the release notes or documentation, that this behavior is intentional. So I assume this is a bug.
Starting with iOS 18, there is a change in how the transition from an underlying view to a UIDocumentInteractionController’s preview view is animated. The transition now scales down the size of the content within the controller’s view, using the center point of the root view as the base of the transformation. This results in a smaller, compressed view centered within the root view, revealing the root view’s background, which is typically white. Even if this background color is adjusted to match elements like the navigation bar, the transformed view has non-rounded corners.
I have not tested this behavior when presenting a UIDocumentInteractionController from a SwiftUI view.
My question to the UIKit framework developers: Is this new behavior of UIDocumentInteractionController an intentional feature, a feature with bugs, or just a bug?
Currently, I have achieve shadow and corner effect for UICollectionViewListCell, using the following code.
UICollectionViewListCell
class NoteCell: UICollectionViewListCell {
override func awakeFromNib() {
super.awakeFromNib()
initShadow()
initCorner()
}
private func updateShadowColor() {
// Determine the shadow color based on the current interface style
let shadowUIColor = UIColor.label
self.layer.shadowColor = shadowUIColor.cgColor
}
private func initShadow() {
// https://www.hackingwithswift.com/example-code/uikit/how-to-add-a-shadow-to-a-uiview
self.layer.shadowOpacity = 0.3
self.layer.shadowOffset = CGSize(width: 0.5, height: 0.5)
self.layer.shadowRadius = 2
self.layer.masksToBounds = false
self.updateShadowColor()
// Remove the following two lines if you experience any issues with shadow rendering:
self.layer.shouldRasterize = true
self.layer.rasterizationScale = UIScreen.main.scale
}
private func initCorner() {
var backgroundConfig = UIBackgroundConfiguration.listPlainCell()
backgroundConfig.backgroundColor = .systemBackground
backgroundConfig.cornerRadius = 16
self.backgroundConfiguration = backgroundConfig
}
layout
private func layoutConfig() -> UICollectionViewCompositionalLayout {
let layout = UICollectionViewCompositionalLayout { section, layoutEnvironment in
var config = UICollectionLayoutListConfiguration(appearance: .plain)
config.headerMode = .none
config.footerMode = .none
config.showsSeparators = false
config.headerTopPadding = 0
config.backgroundColor = nil
config.trailingSwipeActionsConfigurationProvider = { [weak self] indexPath in
guard let self = self else { return nil }
// Knowing what we are tapping at.
var snapshot = dataSource.snapshot()
let sectionIdentifier = snapshot.sectionIdentifiers[indexPath.section]
let itemIdentifiers = snapshot.itemIdentifiers(inSection: sectionIdentifier)
let itemIdentifier: NoteWrapper = itemIdentifiers[indexPath.item]
let deleteHandler: UIContextualAction.Handler = { action, view, completion in
completion(true)
// TODO:
//snapshot.reloadItems([itemIdentifier])
}
let deleteAction = UIContextualAction(style: .normal, title: "Trash", handler: deleteHandler)
var swipeActionsConfiguration = UISwipeActionsConfiguration(actions: [
deleteAction,
])
deleteAction.image = UIImage(systemName: "trash")
deleteAction.backgroundColor = UIColor.systemRed
swipeActionsConfiguration.performsFirstActionWithFullSwipe = false
return swipeActionsConfiguration
}
// https://developer.apple.com/forums/thread/759987
let layoutSection = NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
layoutSection.interGroupSpacing = 16 // Distance between item.
layoutSection.contentInsets = NSDirectionalEdgeInsets(
top: 16, // Distance between 1st item and its own header.
leading: 16,
bottom: 16, // Distance of last item and other header/ bottom edge.
trailing: 16
)
return layoutSection
}
return layout
}
This is the outcome.
However, when I perform swipe action, the shadow effect is gone.
Do you have any idea how I can resolve such? Thanks.
I use @Binding to sync data between SwiftUI component state and UITable state.
my observations:
while reordering @State variable of the TestView is updating, it can be checked by taping the button
inside the table the data is not updating. 'log2' is always the same on reorder and which is more important the app crashes when I try to remove item.
What to I missing?
import SwiftUI
import UIKit
struct TestView: View {
@State var items = ["item 1", "item 2", "item 3", "item 4", "item 5"]
var body: some View {
VStack {
Button("Print Items") { print("log1", items) }
ReorderableListView(
items: $items
) { item in
Text(item)
}
}
}
}
private struct ReorderableListView<Content: View>: UIViewControllerRepresentable {
@Binding var items: [String]
let content: (String) -> Content
class Coordinator: NSObject, UITableViewDataSource, UITableViewDelegate {
var parent: ReorderableListView
init(parent: ReorderableListView) {
self.parent = parent
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
print("log2", parent.items)
return parent.items.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
let hostingController = UIHostingController(rootView: parent.content(parent.items[indexPath.row]))
hostingController.view.backgroundColor = .clear
cell.contentView.subviews.forEach { $0.removeFromSuperview() }
cell.contentView.addSubview(hostingController.view)
cell.separatorInset = UIEdgeInsets(top: 0, left: 15, bottom: 0, right: 15)
if indexPath.row == self.parent.items.count - 1 {
cell.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: .greatestFiniteMagnitude)
}
hostingController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
hostingController.view.topAnchor.constraint(equalTo: cell.contentView.topAnchor),
hostingController.view.bottomAnchor.constraint(equalTo: cell.contentView.bottomAnchor),
hostingController.view.leadingAnchor.constraint(equalTo: cell.contentView.leadingAnchor),
hostingController.view.trailingAnchor.constraint(equalTo: cell.contentView.trailingAnchor)
])
return cell
}
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
let movedObject = parent.items.remove(at: sourceIndexPath.row)
parent.items.insert(movedObject, at: destinationIndexPath.row)
}
func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
return true
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
parent.items.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
}
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func makeUIViewController(context: Context) -> UITableViewController {
let tableViewController = UITableViewController()
tableViewController.tableView.dataSource = context.coordinator
tableViewController.tableView.delegate = context.coordinator
tableViewController.tableView.register(CustomTableViewCell.self, forCellReuseIdentifier: "Cell")
tableViewController.tableView.isEditing = true
return tableViewController
}
func updateUIViewController(_ uiViewController: UITableViewController, context: Context) {
uiViewController.tableView.reloadData()
}
}
private class CustomTableViewCell: UITableViewCell {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
}
override func layoutSubviews() {
super.layoutSubviews()
superview?.subviews.filter({ "\(type(of: $0))" == "UIShadowView" }).forEach { (sv: UIView) in
sv.removeFromSuperview()
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
#Preview {
TestView()
}
Hello everyone!
I was implementing a MFMessageComposeViewController to send messages.
Currently I'm observing behaviour that attachments button is always disabled. But thing is that I'm showing MFMessageComposeViewController only when canSendText() && canSendAttachments() are true.
if MFMessageComposeViewController.canSendText() && MFMessageComposeViewController.canSendAttachments() {
let composeVC = MFMessageComposeViewController()
composeVC.messageComposeDelegate = self
composeVC.body = "Test message"
self.present(composeVC, animated: true, completion: nil)
}
I've checked that mms are enabled.
I found iPadOS18 displayed navigation bar incorrectly when transition from screen with hidden navigation bar to screen that show navigation bar.
I have 2 ViewController: FirstViewController and SecondViewController.
FirstViewController navigationBar set isHidden to be true (hidden) and
SecondViewController navigationBar set isHidden to be false (showing).
When transition from FirstViewController to SecondViewController, the navigation bar is displayed incorrectly as shown in picture below:
Actual
Expected
Note
I set hide navigation bar in viewWillAppear() in both ViewController
override func viewWillAppear(_ animated: Bool) {
navigationController?.setNavigationBarHidden(..., animated: true)
}
source code: https://github.com/ornthita/TestTabbar
I'm facing an accessibility issue, where when I call UIViewController.addChild(_:) and pass in another instance of a UIViewController, the VoiceOver focus is jumping to the "Back" button in the navigation bar. How might one go about avoid this behaviour and having the accessibility/voiceover focus remain where it was at the time of adding the child?
I am building an app about photos and
I want to create a photo sharing feature like Apple's Photos App.
Please see Steps to Reproduce and attached project.
The current share method has the following issues
The file name of the shared photo changes to “FullSizeRender”.
The creation and update dates of shared photos will change to the date they were edited or shared.
I want to ensure that the following conditions are definitely met
Share the latest edited version.
The creation date should be when the original photo was first created.
How can I improve the code?
STEPS TO REPRODUCE
class PHAssetShareManager {
static func shareAssets(_ assets: [PHAsset], from viewController: UIViewController, sourceView: UIView) {
let manager = PHAssetResourceManager.default()
var filesToShare: [URL] = []
let group = DispatchGroup()
for asset in assets {
group.enter()
getAssetFile(asset, resourceManager: manager) { fileURL in
if let fileURL = fileURL {
filesToShare.append(fileURL)
}
group.leave()
}
}
group.notify(queue: .main) {
self.presentShareSheet(filesToShare, from: viewController, sourceView: sourceView)
}
}
private static func getAssetFile(_ asset: PHAsset, resourceManager: PHAssetResourceManager, completion: @escaping (URL?) -> Void) {
print("getAssetFile")
let resources: [PHAssetResource]
switch asset.mediaType {
case .image:
if asset.mediaSubtypes.contains(.photoLive) {
// let editedResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .fullSizePairedVideo }
// let originalResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .pairedVideo }
let editedResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .fullSizePhoto }
let originalResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .photo }
resources = editedResources.isEmpty ? originalResources : editedResources
} else {
let editedResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .fullSizePhoto }
let originalResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .photo }
resources = editedResources.isEmpty ? originalResources : editedResources
}
case .video:
let editedResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .fullSizeVideo }
let originalResources = PHAssetResource.assetResources(for: asset).filter { $0.type == .video }
resources = editedResources.isEmpty ? originalResources : editedResources
default:
print("Unsupported media type")
completion(nil)
return
}
guard let resource = resources.first else {
print("No resource found")
completion(nil)
return
}
let fileName = resource.originalFilename
let tempDirectoryURL = FileManager.default.temporaryDirectory
let localURL = tempDirectoryURL.appendingPathComponent(fileName)
// Delete existing files and reset cache
if FileManager.default.fileExists(atPath: localURL.path) {
do {
try FileManager.default.removeItem(at: localURL)
} catch {
print("Error removing existing file: \(error)")
}
}
let options = PHAssetResourceRequestOptions()
options.isNetworkAccessAllowed = true
resourceManager.writeData(for: resource, toFile: localURL, options: options) { (error) in
if let error = error {
print("Error writing asset data: \(error)")
completion(nil)
} else {
completion(localURL)
}
}
}
private static func presentShareSheet(_ items: [Any], from viewController: UIViewController, sourceView: UIView) {
print("presentShareSheet")
let activityViewController = UIActivityViewController(activityItems: items, applicationActivities: nil)
if UIDevice.current.userInterfaceIdiom == .pad {
activityViewController.popoverPresentationController?.sourceView = sourceView
activityViewController.popoverPresentationController?.sourceRect = sourceView.bounds
}
viewController.present(activityViewController, animated: true, completion: nil)
}
}```
Input issues occur in the textField while using a bilingual keyboard (Korean and English).
System settings:
Keyboard: Bilingual (Korean & English)
Project environment:
Xcode >= 15.4 & iOS >= 18.0
Base localization: Korean
// UITextField settings:
textField.keyboardType = .decimalPad // or .phonePad
self.textField.addTarget(self, action: #selector(self.textFieldEditingChanged), for: .editingChanged)
@objc
func textFieldEditingChanged() {
self.textField.text = "\(self.textField.text!)-"
}
/*
Input: 123456
Expected: 1-2-3-4-5-6-
Result: 11111123456-
*/
The issue occurs when modifying the text of the textField in the editingChanged event.
In the above code, a hyphen is appended to the input with each character.
When typing 123456, the expected result is:
Input: 1 → Result: 1-
Input: 2 → Result: 1-2-
…
Input: 6 → Result: 1-2-3-4-5-6-
However, the actual result is 11111123456-.
Another example:
@objc
func textFieldEditingChanged() {
print("before", self.textField.text!)
self.textField.text = self.textField.text?.replacingOccurrences(of: "0", with: "1")
print("after", self.textField.text!)
}
When inputting 0 1 0 sequentially, the output is:
before 0 after 1
before 01 after 11
before 010 after 111
The value of "after" matches expectations,
but the "before" value reverts to 0 on the next input, even though it appears as 1 on the UI.
When the bilingual keyboard option is turned off or the base localization is set to something other than Korea, the issue does not occur.
Could you provide information on whether this issue will be resolved in the next iOS version, or if there is a workaround?
Hi,
We are going to create a tvOS App with portrait display(HDMI screen will rotate 90 degree).
It seems there is no rotate setting in tvOS18, neither Xcode provide relative support.
As our investigation, we might need to rotate each UIKit component 90 degree by code to archive it.
Is there any better suggestion?
Thanks.
I am trying to change UITabBar background color runtime as theme changed. It is already working in iOS 17 as I am updating UITabBar.appearance().barTintColor and tintColor
But for iOS first i need to change because I don't want that new elevated tabbar so I create custom tabbar controller as described in
https://stackoverflow.com/questions/78631030/how-to-disable-the-new-uitabbarcontroller-view-style-in-ipados-18
Accepted Answer by awulf.
And by doing this, My tabbar looks same like Old and it is working in iPhone and ipad for iOS 16, iOS 17 and iOS 18 too.
But the issue is that I am unable to change my tabbar background color.
I have also checked this forum: https://forums.developer.apple.com/forums/thread/761056
But not able to change
I have set below 3 properties but no effect
let appearance = UITabBar.appearance()
appearance.backgroundColor =
appearance.barTintColor =
appearance.tintColor =
I have created CustomTabBarController in storyboard and all working fine
Also the appearance changed only once per application lifecycle.
It will change color by restarting the app then it will pick last selected theme and the colors are changed.
but not able to change colors runtime
I have also did below code for reloading purpose
tabBar.setNeedsLayout()
tabBar.setNeedsDisplay()
But nothing work
I notice that the UIControlEventEditingChanged action will be called twice under Chinese or Japanese when click confirm button of the UITextfield's keyboard. While for other languages such as English it only be called once. Could anyone can explain the detail for it?
In iOS18, WKWebView's default cookie SameSite value is Lax. Prior to iOS18, the default value is None.
Is this intentional, or a bug? This change is not documented anywhere.
I made a sample XCode project (ViewController code below) to show this change. It loads www.apple.com into a WKWebView and prints cookies. That site has several cookies, but it only explicitly sets SameSite to None for one cookie, s_vi. Every other cookie relies on default WKWebView behavior. When looking at cookies, either in the console or in Safari's Web Inspector, the SameSite value differs. If older than iOS18, every cookie has SameSite of None. If iOS18, all cookies except s_vi have SameSIte of Lax.
I also tried manually setting the following cookies:
testCookie-none with SameSite set to None
testCookie-lax with SameSite set to Lax
testCookie-strict with SameSite set to Strict
testCookie- with SameSite set to an empty string
When looking at these cookies, testCookie-none and testCookie- have their SameSite of None if older than iOS18, but are both Lax in iOS18. So, it seems we cannot manually set the SameSIte to None either.
I realize updating the server to return the SameSite value would resolve this. However, in my app where I'm struggling with this issue, that server is Salesforce. Only they can update their response headers. Since this change isn't documented by Apple, I am assuming it is a bug and not intentional. Are there any workarounds? Any input by Apple on a fix?
Below is the ViewController code, and images of the cookies in Safari's Web Inspector.
import UIKit
import WebKit
class ViewController: UIViewController, WKNavigationDelegate {
var webView: WKWebView!
override func loadView() {
// Create WKWebView
let config = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: config)
// Allow inspection in Safari debugger
webView.isInspectable = true
// Track the request to load our website
webView.navigationDelegate = self
// Manually add four cookies:
// testCookie-none with SameSite set to None
// testCookie-lax with SameSite set to Lax
// testCookie-strict with SameSite set to Strict
// testCookie- with SameSite set to an empty string
addTestCookies()
view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
// Load a website
let urlString = "https://www.apple.com"
self.webView.load(URLRequest(url: URL(string:urlString)!))
}
// Once the website loads, print the cookies.
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
WKWebsiteDataStore.default().httpCookieStore.getAllCookies { cookies in
for cookie in cookies {
print(cookie)
}
}
}
/*
Manually add the following cookies for domain .apple.com
testCookie-none with SameSite set to None
testCookie-lax with SameSite set to Lax
testCookie-strict with SameSite set to Strict
testCookie- with SameSite set to an empty string
In older iOS versions, both testCookie-none and testCookie- will have their SameSite as none.
In iOS18, no cookie will have SameSite as None.
*/
func addTestCookies()
{
let httpCookieStore = WKWebsiteDataStore.default().httpCookieStore
for sameSitePolicy in ["none", "lax", "strict", ""] {
httpCookieStore.setCookie(HTTPCookie(properties: [
HTTPCookiePropertyKey.path: "/",
HTTPCookiePropertyKey.name: "testCookie-"+sameSitePolicy,
HTTPCookiePropertyKey.value: "1",
HTTPCookiePropertyKey.domain: ".apple.com",
HTTPCookiePropertyKey.secure: true,
HTTPCookiePropertyKey.sameSitePolicy: sameSitePolicy
])!)
}
}
}
Previously this code would trigger fine on pressesBegan in iOS 17 and earlier versions, but no longer works in iOS 18. How can I start capturing pressesBegan in iOS 18? It seems like UIResponder is just not capturing the keyboard anymore?
struct ContentView: View {
var body: some View {
KeyBoardView()
}
}
//To Use in SwiftUI
struct KeyBoardView: UIViewRepresentable{
func makeUIView(context: Context) -> KeyEventView {
KeyEventView()
}
func updateUIView(_ uiView: KeyEventView, context: Context) {
}
class KeyEventView: UIView {
init() {
super.init(frame: CGRect(x: 0, y: 0, width: 0, height: 0))
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func pressesBegan(_ presses: Set<UIPress>, with event: UIPressesEvent?)
{
print("test")
}
}
}
Hi all,
Firebase statistics show that some crashes seem to occur suddenly. Can you give me some suggestions?
Users also meet the following requirements:
iOS18 and above
RTL language
From the stack frame, the crash occurred in the transition animation project, but I did not reproduce this stack frame
A very small number of users can experience it twice
The crashed page is relatively complex, and it is a mixture of auto-layout and frame
I retrieved some other articles, but they don’t seem to be the same problem
https://developer.apple.com/forums/thread/693118
https://stackoverflow.com/questions/56027014/collectionview-crashing-in-nsisengine-after-a-few-scrolls
Thank you for reading, looking forward to your reply ;)
CoreAutoLayout: _engineVar_rawRemove
We're trying to implement a backup/restore data feature in our business productivity iPad app using UIDocumentPickerViewController and AppleArchive, but discovered AppleArchive crashes instead of failing gracefully when decrypting a corrupt archive.
As described in forum post 765101, UIDocumentPickerViewController can handoff a corrupt copy of an archive to UIDocumentPickerDelegate under specific circumstances.
We've duplicated this behavior with iPadOS 16.6.1 and 17.7 when building our app with Xcode 15.4 targeting minimum deployment of iPadOS 16. We haven't tested this with the bleeding edge iPadOS 18.
Our app is primarily Objective-C, but it utilizes the Swift-based AppleArchive 'EncryptingAndDecryptingDirectories' sample code associated with WWDC21 session:
10233: Bring Encrypted Archives and Performance Improvements to Your App with Accelerate.
The WWDC21 'EncryptingAndDecryptingDirectories' Swift sample project crashes in a similar manner when a corrupt archive file created by UIDocumentPickerViewController is dropped into the sample app's window for decryption (see attached crash log).
Does anyone know if there's a workaround for the 'EncryptingAndDecryptingDirectories' sample project to prevent AppleArchive from crashing when decrypting a corrupt archive?
crash log.txt
We're trying to implement a backup/restore data feature in our business productivity iPad app using UIDocumentPickerViewController and AppleArchive, but discovered odd behavior of [UIDocumentPickerViewController initForOpeningContentTypes: asCopy:YES] when reading large archive files from a USB drive.
We've duplicated this behavior with iPadOS 16.6.1 and 17.7 when building our app with Xcode 15.4 targeting minimum deployment of iPadOS 16. We haven't tested this with bleeding edge iPadOS 18.
Here's our Objective-C code which presents the picker:
NSArray* contentTypeArray = @[UTTypeAppleArchive];
UIDocumentPickerViewController* docPickerVC = [[UIDocumentPickerViewController alloc] initForOpeningContentTypes:contentTypeArray asCopy:YES];
docPickerVC.delegate = self;
docPickerVC.allowsMultipleSelection = NO;
docPickerVC.shouldShowFileExtensions = YES;
docPickerVC.modalPresentationStyle = UIModalPresentationPopover;
docPickerVC.popoverPresentationController.sourceView = self.view;
[self presentViewController:docPickerVC animated:YES completion:nil];
The UIDocumentPickerViewController remains visible until the selected external archive file has been copied from the USB drive to the app's local tmp sandbox. This may take several seconds due to the slow access speed of the USB drive. During this time the UIDocumentPickerViewController does NOT disable its tableview rows displaying files found on the USB drive. Even the most patient user will tap the desired filename a second (or third or fourth) time since the user's initial tap appears to have been ignored by UIDocumentPickerViewController, which lacks sufficient UI feedback showing it's busy copying the selected file.
When the user taps the file a second time, UIDocumentPickerViewController apparently begins to copy the archive file once again. The end result is a truncated copy of the selected file based on the time between taps. For instance, a 788 MB source archive may be copied as a 56 MB file. Here, the UIDocumentPickerDelegate receives a 56 MB file instead of the original 788 MB of data.
Not surprisingly, AppleArchive fails to decrypt the local copy of the archive because it's missing data. Instead of failing gracefully, AppleArchive crashes in AAArchiveStreamClose() (see forums post 765102 for details).
Does anyone know if there's a workaround for this strange behavior of UIDocumentPickerViewController?
Can anyone help me to resolve this issue?
I have two collectionviews in a tableview and each time you try to scroll the collecctionview after clicking a cell, it crashes with the following error:
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Expected dequeued view to be returned to the collection view in preparation for display. When the collection view's data source is asked to provide a view for a given index path, ensure that a single view is dequeued and returned to the collection view. Avoid dequeuing views without a request from the collection view. For retrieving an existing view in the collection view, use -[UICollectionView cellForItemAtIndexPath:] or -[UICollectionView supplementaryViewForElementKind:atIndexPath:]