On iPhone devices with dynamic islands (e.g. iPhone 15 Pro Max), the proximity sensor takes about 3 seconds to activate, is this normal?
The iPhone 13 responds almost instantly, but the iPhone 15 Pro Max seems to take a while.
// Shared instance for global access (optional)
static let shared = ProximitySensorManager()
// Proximity sensor activation flag
private(set) var isSensorEnabled: Bool = false
// Start observing proximity sensor changes
func enableProximitySensor(observer: Any) {
guard !isSensorEnabled else { return }
isSensorEnabled = true
UIDevice.current.isProximityMonitoringEnabled = true
NotificationCenter.default.addObserver(
observer,
selector: #selector(proximityStateChanged),
name: UIDevice.proximityStateDidChangeNotification,
object: nil
)
}
// Stop observing proximity sensor changes
func disableProximitySensor(observer: Any) {
guard isSensorEnabled else { return }
isSensorEnabled = false
UIDevice.current.isProximityMonitoringEnabled = false
NotificationCenter.default.removeObserver(
observer,
name: UIDevice.proximityStateDidChangeNotification,
object: nil
)
}
// Proximity sensor state change handler
@objc private func proximityStateChanged() {
if UIDevice.current.proximityState {
print("Proximity sensor detected close object")
// Additional functionality can be added here (e.g. lowering the screen brightness)
} else {
print("Proximity sensor detected no object")
}
}
deinit {
//disableProximitySensor() // Clean up observer on deinitialization
}
}
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Posts under UIKit tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Steps to reproduce:
From my UINavigationController, call
setViewControllers([vc1], animated: true)
Then later call
setViewControllers([vc2], animated: true)
Results:
In iOS 17, this behaves fine. In iOS 18, it crashes the UINavigationController.
Both log: Attempt to present * on * which is already presenting *
Workaround:
use setViewControllers(...animated: false)
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?
Problem Description:
In a SwiftUI application, I've wrapped UIKit's UIPageViewController using UIViewControllerRepresentable, naming the wrapped class PagedInfiniteScrollView. This component causes navigation bar elements (title and buttons) to disappear.
This issue only occurs in Low Power Mode on a physical device.
Steps to Reproduce:
Enable Low Power Mode on a physical device and open the app's home page.
From the home page, open a detail sheet containing PagedInfiniteScrollView. This detail page include a navigation title and a toolbar button in the top-right corner. PagedInfiniteScrollView supports horizontal swiping to switch pages.
Tap the toolbar button in the top-right corner of the detail page to open an edit sheet.
Without making any changes, close the edit sheet and return to the detail page. On the detail page, swipe left and right on the PagedInfiniteScrollView.
Expected Result:
When swiping the PagedInfiniteScrollView, the navigation title and top-right toolbar button of the detail page should remain visible.
Actual Result:
When swiping the PagedInfiniteScrollView, the navigation title and top-right toolbar button of the detail page disappear.
import SwiftUI
@main
struct CalendarApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
import SwiftUI
struct ContentView: View {
@State private var showDetailSheet = false
@State private var currentPage: Int = 0
var body: some View {
NavigationStack {
Button {
showDetailSheet = true
} label: {
Text("show Calendar sheet")
}
.sheet(isPresented: $showDetailSheet) {
DetailSheet(currentPage: $currentPage)
}
}
}
}
struct DetailSheet: View {
@Binding var currentPage: Int
@State private var showEditSheet = false
var body: some View {
NavigationStack {
PagedInfiniteScrollView(content: { pageIndex in
Text("\(pageIndex)")
.frame(width: 200, height: 200)
.background(Color.blue)
},
currentPage: $currentPage)
.sheet(isPresented: $showEditSheet, content: {
Text("edit")
})
.navigationTitle("Detail")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItemGroup(placement: .topBarTrailing) {
Button {
showEditSheet = true
} label: {
Text("Edit")
}
}
}
}
}
}
import SwiftUI
import UIKit
struct PagedInfiniteScrollView<Content: View>: UIViewControllerRepresentable {
typealias UIViewControllerType = UIPageViewController
let content: (Int) -> Content
@Binding var currentPage: Int
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIPageViewController {
let pageViewController = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal)
pageViewController.dataSource = context.coordinator
pageViewController.delegate = context.coordinator
let initialViewController = UIHostingController(rootView: IdentifiableContent(index: currentPage, content: { content(currentPage) }))
pageViewController.setViewControllers([initialViewController], direction: .forward, animated: false, completion: nil)
return pageViewController
}
func updateUIViewController(_ uiViewController: UIPageViewController, context: Context) {
let currentViewController = uiViewController.viewControllers?.first as? UIHostingController<IdentifiableContent<Content>>
let currentIndex = currentViewController?.rootView.index ?? 0
if currentPage != currentIndex {
let direction: UIPageViewController.NavigationDirection = currentPage > currentIndex ? .forward : .reverse
let newViewController = UIHostingController(rootView: IdentifiableContent(index: currentPage, content: { content(currentPage) }))
uiViewController.setViewControllers([newViewController], direction: direction, animated: true, completion: nil)
}
}
class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
var parent: PagedInfiniteScrollView
init(_ parent: PagedInfiniteScrollView) {
self.parent = parent
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let currentView = viewController as? UIHostingController<IdentifiableContent<Content>>, let currentIndex = currentView.rootView.index as Int? else {
return nil
}
let previousIndex = currentIndex - 1
return UIHostingController(rootView: IdentifiableContent(index: previousIndex, content: { parent.content(previousIndex) }))
}
func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? {
guard let currentView = viewController as? UIHostingController<IdentifiableContent<Content>>, let currentIndex = currentView.rootView.index as Int? else {
return nil
}
let nextIndex = currentIndex + 1
return UIHostingController(rootView: IdentifiableContent(index: nextIndex, content: { parent.content(nextIndex) }))
}
func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
if completed,
let currentView = pageViewController.viewControllers?.first as? UIHostingController<IdentifiableContent<Content>>,
let currentIndex = currentView.rootView.index as Int? {
parent.currentPage = currentIndex
}
}
}
}
extension PagedInfiniteScrollView {
struct IdentifiableContent<Content: View>: View {
let index: Int
let content: Content
init(index: Int, @ViewBuilder content: () -> Content) {
self.index = index
self.content = content()
}
var body: some View {
content
}
}
}
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?
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 there! I'm one year into iOS development, and can usually figure out the cause of a crash. However, I've been bumping my head against this one for a while now.
Invalid memory pointer crash
According to this article, the crash (EXC_BAD_ACCESS) happens due to an invalid memory pointer. When I use the atos command to symbolicate the crash report, the line where the crash happens in my app (see line 39 in the full stack trace below) is simply the very first line in MyApp that extends App (annotated with @main) -- but there's no code on that line.
It seems like the error is happening somewhere with UIKit's UIViewController but I can't seem to figure it out.
Could be relevant code
I do have the following class in my app, which helps with hiding the tab bar I use when another view is opened. It might be relevant:
struct HideTabBar: UIViewControllerRepresentable {
var callback: (UITabBar) -> Void
private let proxyController = ViewController()
func makeUIViewController(context: UIViewControllerRepresentableContext<HideTabBar>) ->
UIViewController {
proxyController.callback = callback
return proxyController
}
func updateUIViewController(_ uiViewController: UIViewController, context: UIViewControllerRepresentableContext<HideTabBar>) {
}
typealias UIViewControllerType = UIViewController
private class ViewController: UIViewController {
var callback: (UITabBar) -> Void = { _ in }
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if let tabBar = self.tabBarController {
self.callback(tabBar.tabBar)
}
}
}
}
Full stack trace:
Exception Type: EXC_BAD_ACCESS (SIGSEGV)
Exception Subtype: KERN_INVALID_ADDRESS at 0x0000000000000010
Exception Codes: 0x0000000000000001, 0x0000000000000010
VM Region Info: 0x10 is not in any region. Bytes before following region: 4363845616
REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
UNUSED SPACE AT START
--->
Termination Reason: SIGNAL 11 Segmentation fault: 11
Terminating Process: exc handler [664]
Triggered by Thread: 0
Kernel Triage:
VM - (arg = 0x3) mach_vm_allocate_kernel failed within call to vm_map_enter
Thread 0 name: Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0 libobjc.A.dylib 0x19205fc20 objc_msgSend + 32
1 UIKitCore 0x19c697a68 -[UIViewController dealloc] + 860
2 UIKitCore 0x19c863c80 -[UINavigationController dealloc] + 296
3 UIKitCore 0x19c863b34 -[_UISplitViewControllerColumnContents .cxx_destruct] + 44
4 libobjc.A.dylib 0x192061acc object_cxxDestructFromClass(objc_object*, objc_class*) + 116
5 libobjc.A.dylib 0x192060f00 objc_destructInstance + 80
6 libobjc.A.dylib 0x192060ea4 _objc_rootDealloc + 80
7 CoreFoundation 0x19a0fc730 cow_cleanup + 164
8 CoreFoundation 0x19a0fec80 -[__NSDictionaryM dealloc] + 148
9 libobjc.A.dylib 0x192061acc object_cxxDestructFromClass(objc_object*, objc_class*) + 116
10 libobjc.A.dylib 0x192060f00 objc_destructInstance + 80
11 libobjc.A.dylib 0x192060ea4 _objc_rootDealloc + 80
12 UIKitCore 0x19c8f4a54 -[UISplitViewControllerPanelImpl dealloc] + 100
13 libobjc.A.dylib 0x192061acc object_cxxDestructFromClass(objc_object*, objc_class*) + 116
14 libobjc.A.dylib 0x192060f00 objc_destructInstance + 80
15 libobjc.A.dylib 0x192060ea4 _objc_rootDealloc + 80
16 UIKitCore 0x19c457730 -[UIResponder dealloc] + 124
17 UIKitCore 0x19c697ba0 -[UIViewController dealloc] + 1172
18 libobjc.A.dylib 0x192060df4 AutoreleasePoolPage::releaseUntil(objc_object**) + 212
19 libobjc.A.dylib 0x192060c80 objc_autoreleasePoolPop + 260
20 UIKitCore 0x19c4315ec -[_UIAfterCACommitBlock run] + 92
21 UIKitCore 0x19c43149c -[_UIAfterCACommitQueue flush] + 164
22 UIKitCore 0x19c4313b4 _runAfterCACommitDeferredBlocks + 496
23 UIKitCore 0x19c430fec _cleanUpAfterCAFlushAndRunDeferredBlocks + 80
24 UIKitCore 0x19c430efc _UIApplicationFlushCATransaction + 72
25 UIKitCore 0x19c42e660 _UIUpdateSequenceRun + 84
26 UIKitCore 0x19c42e2a4 schedulerStepScheduledMainSection + 172
27 UIKitCore 0x19c42f148 runloopSourceCallback + 92
28 CoreFoundation 0x19a14b834 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
29 CoreFoundation 0x19a14b7c8 __CFRunLoopDoSource0 + 176
30 CoreFoundation 0x19a149298 __CFRunLoopDoSources0 + 244
31 CoreFoundation 0x19a148484 __CFRunLoopRun + 828
32 CoreFoundation 0x19a147cd8 CFRunLoopRunSpecific + 608
33 GraphicsServices 0x1deb951a8 GSEventRunModal + 164
34 UIKitCore 0x19c781ae8 -[UIApplication _run] + 888
35 UIKitCore 0x19c835d98 UIApplicationMain + 340
36 SwiftUI 0x19e33c294 0x19df48000 + 4145812
37 SwiftUI 0x19e2e8860 0x19df48000 + 3803232
38 SwiftUI 0x19e2f461c 0x19df48000 + 3851804
39 MyApp 0x1041f8690 0x1041b0000 + 296592
40 dyld 0x1bd91f154 start + 2356
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:]
I am using Storyboard to present a UIImagePickerController on a view controller (a simple initial view without any navigation or tab bar). Due to a requirement, we need to exclude the arm64 architecture. However, when I try to present the screen, it gets stuck. I am unable to select an image, and the screen becomes inaccessible. It's happening only on simulator.
Does anyone have any solution.
I just finished updating my app to support the new screen sizes for the iPhone 16 series devices (iPhone16 Pro and iPhone 16 Pro Max). In testing the changes, I've come across what I hope is simply a bug in the Xcode 16 simulators. I don't have any actual devices (yet) that I can use to test.
In landscape mode, my app presents a "tab" on the right side of the screen that can be tapped to bring out another view. Activating the tab is based on capturing the screen coordinates from a "tap".
In Xcode 16, using the iPhone16 simulators on IOS 18, the area of the tab does not recognize that a tap has occurred. After hours of banging my head against my laptop, it dawned on me that the area of the screen that hosts the "tab" is in exactly the same location as "unavailable area" that represents the camera on the simulator. I have arrived at the assumption that the issue is that the simulator is treating the same space at the bottom of the device as it treats that reserved area at the top of the screen.
Has anyone else experienced this?
Is this a bug in the simulator or is this expected behavior on the iPhone 16 series devices?
Hi everyone,
I'm working on an iOS app built in Swift using Xcode, where I'm integrating Roboflow's object detection API to extract items from grocery receipts. My goal is to identify key information (like items, total, tax, etc.) from the images of these receipts.
I'm successfully sending images to the Roboflow API and receiving predictions with bounding box data, but when I attempt to extract text from the detected regions (bounding boxes), it appears that the text extraction is failing—no text is being recognized. The issue seems to be that the bounding boxes are either not properly being handled or something is going wrong in the way I process the API response.
Here's a brief breakdown of what I'm doing:
The image is captured, converted to base64, and sent to the Roboflow API.
The API response comes back with bounding boxes for the detected elements (items, date, subtotal, etc.).
The problem occurs when I try to extract the text from the image using the bounding box data—it seems like the bounding boxes are being found, but no text is returned.
I suspect the issue might be happening because the app’s segue to the results view controller is triggered before the OCR extraction completes, or there might be a problem in my code handling the bounding box response.
Response Data:
{
"inference_id": "77134cce-91b5-4600-a59b-fab74350ca06",
"time": 0.09240847699993537,
"image": {
"width": 370,
"height": 502
},
"predictions": [
{
"x": 163.5,
"y": 250.5,
"width": 313.0,
"height": 127.0,
"confidence": 0.9357666373252869,
"class": "Item",
"class_id": 1,
"detection_id": "753341d5-07b6-42a1-8926-ecbc61128243"
},
{
"x": 52.5,
"y": 417.5,
"width": 89.0,
"height": 23.0,
"confidence": 0.8819760680198669,
"class": "Date",
"class_id": 0,
"detection_id": "b4681149-d538-47b1-8700-d9528bf1daa0"
},
...
]
}
And the log showing bounding boxes:
Prediction: ["width": 313, "y": 250.5, "x": 163.5, "detection_id": 753341d5-07b6-42a1-8926-ecbc61128243, "class": Item, "height": 127, "confidence": 0.9357666373252869, "class_id": 1]
No bounding box found in prediction.
I've double-checked the bounding box coordinates, and everything seems fine. Does anyone have experience with using OCR alongside object detection APIs in Swift? Any help on how to ensure the bounding boxes are properly processed and used for OCR would be greatly appreciated!
Also, would it help to delay the segue to the results view controller until OCR is complete?
Thank you!
I have an app that was written in UIKit. It's too large, and it would be much too time consuming at this point to convert it to SwiftUI.
I want to incorporate the new limited contacts into this app. The way it's currently written everything works fine except for showing the limited contacts in the contact picker.
I have downloaded and gone though the Apple tutorial app but I'm having trouble thinking it through into UIKit. After a couple of hours I decided I need help.
I understand I need to pull the contact IDs of the contacts that are in the limited contacts list. Not sure how to do that or how to get it to display in the picker. Any help would be greatly appreciated.
func requestAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void)
{
switch CNContactStore.authorizationStatus(for: .contacts)
{
case .authorized:
completionHandler(true)
case .denied:
showSettingsAlert(completionHandler)
case .restricted, .notDetermined:
CNContactStore().requestAccess(for: .contacts) { granted, error in
if granted
{
completionHandler(true)
} else {
DispatchQueue.main.async { [weak self] in
self?.showSettingsAlert(completionHandler)
}
}
}
// iOS 18 only
case .limited:
completionHandler(true)
@unknown default: break
}
}
// A text field that displays the name of the chosen contact
@IBAction func contact_Fld_Tapped(_ sender: TextField_Designable)
{
sender.resignFirstResponder()
// The contact ID that is saved to the Db
getTheCurrentContactID()
let theAlert = UIAlertController(title: K.Titles.chooseAContact, message: nil, preferredStyle: .actionSheet)
// Create a new contact
let addContact = UIAlertAction(title: K.Titles.newContact, style: .default) { [weak self] _ in
self?.requestAccess { _ in
let openContact = CNContact()
let vc = CNContactViewController(forNewContact: openContact)
vc.delegate = self // this delegate CNContactViewControllerDelegate
DispatchQueue.main.async {
self?.present(UINavigationController(rootViewController: vc), animated: true)
}
}
}
let getContact = UIAlertAction(title: K.Titles.fromContacts, style: .default) { [weak self] _ in
self?.requestAccess { _ in
self?.contactPicker.delegate = self
DispatchQueue.main.async {
self?.present(self!.contactPicker, animated: true)
}
}
}
let editBtn = UIAlertAction(title: K.Titles.editContact, style: .default) { [weak self] _ in
self?.requestAccess { _ in
let store = CNContactStore()
var vc = CNContactViewController()
do {
let descriptor = CNContactViewController.descriptorForRequiredKeys()
let editContact = try store.unifiedContact(withIdentifier: self!.oldContactID, keysToFetch: [descriptor])
vc = CNContactViewController(for: editContact)
} catch {
print("Getting contact to edit failed: \(self!.VC_String) \(error)")
}
vc.delegate = self // delegate for CNContactViewControllerDelegate
self?.navigationController?.isNavigationBarHidden = false
self?.navigationController?.navigationItem.hidesBackButton = false
self?.navigationController?.pushViewController(vc, animated: true)
}
}
let cancel = UIAlertAction(title: K.Titles.cancel, style: .cancel) { _ in }
if oldContactID.isEmpty
{
editBtn.isEnabled = false
}
theAlert.addAction(getContact) // Select from contacts
theAlert.addAction(addContact) // Create new contact
theAlert.addAction(editBtn) // Edit this contact
theAlert.addAction(cancel)
let popOver = theAlert.popoverPresentationController
popOver?.sourceView = sender
popOver?.sourceRect = sender.bounds
popOver?.permittedArrowDirections = .any
present(theAlert,animated: true)
}
func requestAccess(completionHandler: @escaping (_ accessGranted: Bool) -> Void)
{
switch CNContactStore.authorizationStatus(for: .contacts)
{
case .authorized:
completionHandler(true)
case .denied:
showSettingsAlert(completionHandler)
case .restricted, .notDetermined:
CNContactStore().requestAccess(for: .contacts) { granted, error in
if granted
{
completionHandler(true)
} else {
DispatchQueue.main.async { [weak self] in
self?.showSettingsAlert(completionHandler)
}
}
}
// iOS 18 only
case .limited:
completionHandler(true)
@unknown default: break
}
}
// MARK: - Contact Picker Delegate
extension AddEdit_Quote_VC: CNContactPickerDelegate
{
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact)
{
selectedContactID = contact.identifier
let company: String = contact.organizationName
let companyText = company == "" ? K.Titles.noCompanyName : contact.organizationName
contactNameFld_Outlet.text = CNContactFormatter.string(from: contact, style: .fullName)!
companyFld_Outlet.text = companyText
save_Array[0] = K.AppFacing.true_App
setSaveBtn_AEQuote()
}
}
extension AddEdit_Quote_VC: CNContactViewControllerDelegate
{
func contactViewController(_ viewController: CNContactViewController, shouldPerformDefaultActionFor property: CNContactProperty) -> Bool
{
return false
}
func contactViewController(_ viewController: CNContactViewController, didCompleteWith contact: CNContact?)
{
selectedContactID = contact?.identifier ?? ""
if selectedContactID != ""
{
let company: String = contact?.organizationName ?? ""
let companyText = company == "" ? K.Titles.noCompanyName : contact!.organizationName
contactNameFld_Outlet.text = CNContactFormatter.string(from: contact!, style: .fullName)
companyFld_Outlet.text = companyText
getTheCurrentContactID()
if selectedContactID != oldContactID
{
save_Array[0] = K.AppFacing.true_App
setSaveBtn_AEQuote()
}
}
dismiss(animated: true, completion: nil)
}
}
Hi there,
I'm trying to migrate my app to using the UIDocumentViewController so I can use the new launch experience. My app exports a custom file type and uses UIDocument + UIDocumentBrowserViewController.
I tried creating a UIDocumentViewController and making it the root view of my app but it doesn't recognise my custom document type.
class Document_VC: UIDocumentViewController {
var storyCardsDocument: PlotCardDocument? {
self.document as? PlotCardDocument
}
override func viewDidLoad() {
super.viewDidLoad()
configureViewForCurrentDocument()
}
override func documentDidOpen() {
configureViewForCurrentDocument()
}
func configureViewForCurrentDocument() {
guard let document = storyCardsDocument,
!document.documentState.contains(.closed)
&& isViewLoaded else { return }
print("Document opened: \(document.fileURL)")
}
}
The app opens but when I navigate to a document made in a previous version of the app it is greyed out. I also don't see a 'New' button in the launcher view.
To try and see what I was doing wrong, I tested the markdown app sample code. When I make the UIDocumentViewController the root and try to open or create a new markdown document I get the following error:
no document class found. Define the correct UIDocument subclass with the key UIDocumentClass in the info.plist's CFBundleDocumentTypes dictionary.
iOS 18 WKWebView images are not loading, no errors in older versions.
The example while loading HTML is as follows. A problem occurs when you pull an image from a url. To get a URL image you need a cookie or something. I add them too, but it doesn't work on iOS 18. I get the error "An error occurred trying to load the resource." and a blue question mark on the screen.
webView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie)
<html>
<head>
<style>
body {
font-family: -apple-system;
margin: 0;
padding: 0;
text-align: center;
}
img {
width: 100%;
height: auto;
}
</style>
</head>
<body>
<h1>Resim Görüntüleme</h1>
<img src="https://xx.***.xx/example.png">
</body>
</html>
"""
Hello!
I discovered a bug on Catalyst about a three years ago but it still seems to be not fixed. My bug report number is FB9705748.
The Internet is silent on this so I'm even not sure, perhaps it's only me.
So to the problem. When you display UICollectionViewController or UIViewController that contains UICollectionView, interact with the collection view then dismiss the view controller, the displayed view controller isn't released if dismissal is done through navigation bar item.
The problem occurs only when the run target is My Mac (Mac Catalyst). Everything is fine when you run on iOS or via My Mac (Designed for iPad).
The sample project is uploaded to GitHub. It has a video that shows this strange behavior, see the log for 'deinit' messages.
I did have some workaround to fix this but it stops to work, presumable on the new macOS. Also, chances are that it's not only UICollectionView which initiates the glitch, it's just that I only encounter it with collection views.