Construct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.

UIKit Documentation

Post

Replies

Boosts

Views

Activity

UIPageViewController curl transition bug since iOS 16
The effect I'm trying to achieve: https://imgur.com/pyaZlen. Basically, a simultaneous page curl and translation on the x axis (since the video was registered in landscape, the translation appears on the y axis). The page curl animation is performed under the hood whenever setViewControllers method of UIPageViewController is called, while the translation is achieved through UIView.animate by updating constraints. Until iOS 15, this was perfectly fine, however since iOS 16 the animation is laggy and does not work as intended, see below. Regular page curl transition (no translation): https://imgur.com/4CQ3KU8 - the back side of the page is fully visible. This was also the behaviour with translation on iOS 14 and 15. Page curl with translation: https://imgur.com/guMolIe - the back side of the page is partially transparent. The issue is clearly related to the x translation occurring while the curl animation is being performed, as without it everything works fine. Probably this is not the right way to perform multiple animations I assume, however since the page curl happens under the hood I'm not really sure on how to handle it. My question is: how can I achieve a page curl and x translation animations simultaneously? And on a side note, does anyone knows why the strange behaviour I encountered happens only on newer versions of iOS? Sample project which reproduces the issue - note, it is intended to work only in landscape: import UIKit final class ViewController: UIViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate { private var pageController: UIPageViewController? private var pageControllerViewLeadingAnchor: NSLayoutConstraint? override func viewDidLoad() { super.viewDidLoad() // init pageController = UIPageViewController(transitionStyle: .pageCurl, navigationOrientation: .horizontal, options: nil) pageController?.dataSource = self pageController?.delegate = self // adding it addChild(pageController!) view.addSubview(pageController!.view) // constraints pageController?.view.translatesAutoresizingMaskIntoConstraints = false pageController?.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true pageController?.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true pageControllerViewLeadingAnchor = pageController?.view.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: -view.bounds.width/4) pageControllerViewLeadingAnchor?.isActive = true pageController?.view.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) DispatchQueue.main.asyncAfter(deadline: .now()+0.5) { // x translation animation UIView.animate(withDuration: 0.3, animations: { self.pageControllerViewLeadingAnchor?.constant = 0 self.view.layoutIfNeeded() }) // pageController curl animation let vc = UIViewController() let vc2 = UIViewController() vc.view.backgroundColor = .red vc2.view.backgroundColor = .blue self.pageController?.setViewControllers([vc, vc2], direction: .forward, animated: true, completion: nil) } } func pageViewController(_ pageViewController: UIPageViewController, spineLocationFor orientation: UIInterfaceOrientation) -> UIPageViewController.SpineLocation { // setting spine to mid and adding vcs let vc = UIViewController() let vc2 = UIViewController() vc2.view.backgroundColor = .green pageController?.setViewControllers([vc, vc2], direction: .forward, animated: true, completion: nil) pageController?.isDoubleSided = true return .mid } func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { return UIViewController() } func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { return UIViewController() } }
0
0
320
Aug ’23
NSAttributed String Error in iOS 16.3.1 or above the error: Assertion failed: (forceBreakIndex > NSMaxRange(lastResortNode->lineBreak.range)), function -[_NSOptimalLineBreaker _calculateOptimalWrapping], file NSOptimalLineBreaker.m, line 1706.
So i found a bug which is to parse a html string with NSAttributedString and use it in textview using AttributedText. The error is this Assertion failed: (forceBreakIndex > NSMaxRange(lastResortNode->lineBreak.range)), function -[_NSOptimalLineBreaker _calculateOptimalWrapping], file NSOptimalLineBreaker.m, line 1706. The parsing seems to be working fine on iOS 15 or below, but in iOS 16 or above, it's crashed like the error previously mentioned.
2
1
375
Aug ’23
Get UICollectionLayoutSectionOrthogonalScrollingBehaviorGroupPaging like behavior for NSCollectionLayoutItems in UICollectionViewCompositionalLayout?
I have a horizontal section in my compositional layout with three items. 0 ---- 1 ----2 When scrolling toward the center I want the scrolling to snap the item at index 1 to the center of the screen. However I can't figure out how to precisely control horizontal scrolling with compositional layout (it doesn't seem possible to control the contentOffset of horizontal scrolling). When I enable paging using UICollectionLayoutSectionOrthogonalScrollingBehaviorPaging the page size assumes full device width and paging works for the item at index 0 or 2 but then the item at index 1 can never be displayed fully on screen (only one half of its width can be shown at a given time). I tried adding leading and trailing space to the group but that didn't work. When I try the UICollectionLayoutSectionOrthogonalScrollingBehaviorGroupPaging the section is displayed with the item at index 1 centered but scrolling doesn't work. I think what I'm looking for is UICollectionLayoutSectionOrthogonalScrollingBehaviorGroupPaging but at the item level or to be able to adjust the contentOffset on the scroll view at the end of dragging. Is there any way I can programmatically access the scroll view being using for horizontal scrolling? I see in the visibleItemsInvalidationHandler I'm able to get the content offset but I'm not able to change it to support snapping.
0
0
429
Aug ’23
viewDidLayoutSubviews being called many times on orientation change in UIViewControllerRepresentable
I'm trying to implement a zoomable image in SwiftUI to display in a page view like the iOS photos app. I'm using UIViewControllerRepresentable to wrap a controller containing a UIScrollView to achieve this, and I'm running into a strange problem with the viewDidLayoutSubviews method being called way to many times when the device rotates. As far as I can tell, this is the cause of some animation problems I'm having with the scroll view. After some experimentation I found a minimal reproducible example that happens to be extremely minimal: class ViewController: UIViewController { override func viewDidLayoutSubviews() { print("viewDidLayoutSubviews: \(self.view.bounds)") } } struct Representable: UIViewControllerRepresentable { func makeUIViewController(context: Context) -> ViewController { return ViewController() } func updateUIViewController(_ uiViewController: ViewController, context: Context) { } } struct ContentView: View { var body: some View { Representable() } } Launching the app and rotating the device once results in viewDidLayoutSubviews being called over 30 times. Interestingly, based on the values being printed, it seems that the bounds of the view are changing as the rotation animation happens. Testing the same code in a fully UIKit application results in expected output: viewDidLayoutSubviews: (0.0, 0.0, 393.0, 852.0) viewDidLayoutSubviews: (0.0, 0.0, 852.0, 393.0) viewDidLayoutSubviews is called once before and once after the orientation change. Also worth noting, the problem is much less severe on iOS 17 (previous tests have been on iOS 16). viewDidLayoutSubviews is called more than expected (5 times), but not enough to break anything, and my zoomable image view works fine on iOS 17. So is this just a bug with SwiftUI on iOS 16? Are there any workarounds? Unfortunately I can't just develop on iOS 17 for now, since it comes with its own collection of SwiftUI bugs that affect my code.
0
0
527
Aug ’23
UICalendarView on Mac Catalyst - Command Key for Multiple Date Selection
A good while back, I created a Mac Catalyst version of an app. The app uses UICalendarView for both iOS and Mac. I have multiple date selection enabled. In the past, I thought I could select multiple dates on the Mac without needing to use the Command key modifier. And now I can't. Is this a change or am I dreaming? How can I go back to being able to select multiple dates without using the command key modifier?
0
0
378
Aug ’23
objc_retain EXC_BAD_ACCESS (KERN_INVALID_ADDRESS) - iOS 16 Crash
Hello, I have been facing a crash happening from iOS 16 onwards. Crash counts have been consistent since iOS 16.0, and I have not been able to figure out the cause. It's most likely a memory leak, and it seems to be due to a bug on Apple's end since there are others facing the same issue from this post: https://developer.apple.com/forums/thread/722734 I have used Instruments but can't draw any conclusions from there. Does anyone have any idea on how we can reduce the crash occurrences from our code? Here is the stack trace: Crashed: com.apple.main-thread 0 libobjc.A.dylib 0x3a7c objc_retain + 16 1 libobjc.A.dylib 0x3a7c objc_retain_x0 + 16 2 UIKitCore 0xbe7940 -[UIKeyboardTaskQueue promoteDeferredTaskIfIdle] + 76 3 UIKitCore 0xbe78cc -[UIKeyboardTaskQueue performDeferredTaskIfIdle] + 32 4 UIKitCore 0x3cd8d8 -[UIKeyboardTaskQueue continueExecutionOnMainThread] + 376 5 Foundation 0x3b7ac __NSThreadPerformPerform + 264 6 CoreFoundation 0xd3128 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 28 7 CoreFoundation 0xdf7b4 __CFRunLoopDoSource0 + 176 8 CoreFoundation 0x645e8 __CFRunLoopDoSources0 + 244 9 CoreFoundation 0x7a0d4 __CFRunLoopRun + 828 10 CoreFoundation 0x7f3ec CFRunLoopRunSpecific + 612 11 GraphicsServices 0x135c GSEventRunModal + 164 12 UIKitCore 0x39d6e8 -[UIApplication _run] + 888 13 UIKitCore 0x39d34c UIApplicationMain + 340 14 0x21738 main + 43 (main.m:43) 15 ??? 0x1c2d4adec (Missing)
0
0
690
Aug ’23
Fatal Exception: NSInvalidArgumentException -[NSCountableTextLocation compare:] receiving unmatching type (null)
Hi, We are getting a lot of these crashes in our app. Not really pointing to any screen, hard to figure out where the problem is! Please help with some pointers to figure out and solve this issue. Its happening in PROD and affecting mostly iOS 16 users. Complete stacktrace is attached. Fatal Exception: NSInvalidArgumentException 0 CoreFoundation 0x92d1c __exceptionPreprocess 1 libobjc.A.dylib 0x14ee4 objc_exception_throw 2 CoreFoundation 0xe5f08 __CFDictionaryCreateGeneric 3 UIFoundation 0x1c090 -[NSCountableTextLocation compare:] 4 UIKitCore 0x208b0 -[_UIModernTextLayoutController comparePosition:toPosition:] 5 UIKitCore 0x2080c -[UITextInputController comparePosition:toPosition:] 6 UIKitCore 0x2044c -[UIFieldEditor comparePosition:toPosition:] 7 UIKitCore 0x203b8 -[UITextField comparePosition:toPosition:] 8 UIKitCore 0x10728f4 -[UITextInteractionAssistant(UITextInteractionAssistant_Internal) scheduleChineseTransliteration] 9 UIKitCore 0x10a9b88 -[UITextField _transliterateChinese:] 10 UIKitCore 0xdbd47c +[UIPasteboard _performAsDataOwnerForAction:responder:block:] 11 UIKitCore 0xad1fb8 -[UICalloutBar buttonPressed:] 12 UIKitCore 0xad0bc8 -[UICalloutBarButton fadeAndSendActionWithAuthenticationMessage:] 13 Foundation 0x34b40 __NSFireDelayedPerform 14 CoreFoundation 0xa7268 CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION 15 CoreFoundation 0x30b08 __CFRunLoopDoTimer 16 CoreFoundation 0x2b6c0 __CFRunLoopDoTimers 17 CoreFoundation 0xb3b4 __CFRunLoopRun 18 CoreFoundation 0x1e250 CFRunLoopRunSpecific 19 GraphicsServices 0x1988 GSEventRunModal 20 UIKitCore 0x4e5a94 -[UIApplication _run] 21 UIKitCore 0x27efd4 UIApplicationMain 22 EssoProd 0x2b08c main + 15 (AppDelegate.swift:15) 23 ??? 0x1054b44d0 (Missing) stacktrace copy.txt
1
0
494
Aug ’23
iOS 17 beta 1 - 5 | Increasing layer speed prevents modal and some animation callbacks from getting called
When using Xcode 15 beta 6 / iOS 17 beta 5, it appears modal presentation and dismissal callbacks are sometimes not getting called. This is noticeable in our test suite where we artificially speed up animations via setting a high window layer speed (window.layer.speed = 100). Example: // Test results: // - Xcode15 beta 1-6: ❌ fails // - Xcode14.3.1: ✅ passes func test_modalPresentation_withFastAnimations() throws { // Given let root = try findActiveWindowRootViewController() let presentation = expectation(description: "Modal Presented") let dismissal = expectation(description: "Modal Dismissed") let modal = UIViewController() // When // ---- // updating layer speed on iOS 17.0 beta results // in presentation / dismissal callbacks getting omitted // subsequently failing tests due to unfulfilled expectations root.view.window?.layer.speed = 100 // ---- root.present(modal, animated: true) { presentation.fulfill() modal.dismiss(animated: true) { dismissal.fulfill() } } // Then wait(for: [presentation, dismissal], timeout: 4.0) } Context: We have a large number of UI tests and resort to increasing the layer speed to speed up the test runtime. Additional Notes: This seems to not affect .fullScreen modal presentation styles Similar issues were noticed with some animation callbacks getting omitted This has been noticed since Xcode 15 / iOS 17 beta 1 Feedback + sample project FB12362774 Is this an issue or expected behaviour going forward? Thanks!
0
1
479
Aug ’23
How do I highlight a property in CNContactViewCotnroller?
The documentation for hightlightProperty(withKey:identifier:) describes the parameter "key" as the "Key of the property to highlight." I believe that refers to the CNKeyDescriptor, such as CNContactGivenNameKey, which can cast from a type CNKeyDescriptor to String. The documentation for identifier is "the value to highlight". I believe an example of that would be "John" as the given name. Am I correct about all this? In any case, I'm not able to highlight an email property when I use CNContactEmailAddresses as the key, and an actual email address as the identifier. I have also tried using the identifier property of CNLabeledValue, which is how an email address is stored. I can't find anything on the internet to explain this. I didn't even find a similar question, except my own question asking this exact same question about two months ago. Anyone have any idea or a good answer for this?
0
0
475
Aug ’23
iOS crash with UIMoreNavigationController
I am getting a crash in my iOS Storyboard app which is easily reproducible. When I enable Zombie Objects, this is the crash message I get. 2023-08-09 21:25:30.736022+1000 ThingyTwo[31860:4546795] *** -[UITabBarController removeChildViewController:]: message sent to deallocated instance 0x14b830000 (lldb) It happens when: A UITabBarController is placed within a UINavigationController. The UITabBarController has more than 5 view controllers, which then internally uses a UIMoreNavigationController to display the remainder. The UINavigationController is removed from the view hierarchy. It doesn't crash 100% of the time, usually somewhere between 20% and 80%. I have created a bare-bones implementation almost entirely as a storyboard. https://github.com/adamroyle/more-controller-crash Run the project, click the "Show" button, and then click the "Dismiss" button. Keep repeating this until it crashes, it shouldn't take long. Please let me know if you know of any simple workaround to this?
2
1
345
Aug ’23
IOS UIkit ViewDidLayout Calls On Handle Drag
I am a new uikit developer. I have a problem on my app. App has 2 different parts. Rectangle view and button. Rectangle view can drag with pan touch gesture. Button can change own image with tap gestures. When user taps the button, it changes own image. But when I tap the button, rectangle view moves to the at the beginning position.(view did load position). I checked logs and I see viewDidLayout methods calling when I tap the button. How can I handle this problem, is there anyone help me ? Thanks a lot. import UIKit final class SampleViewController: UIViewController { private var isTapped: Bool = false let button: UIButton = { let button = UIButton() let image = UIImageView(image: UIImage(systemName: "play")) button.translatesAutoresizingMaskIntoConstraints = false button.backgroundColor = .yellow return button }() let littleView: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false view.layer.borderColor = UIColor.red.cgColor view.layer.borderWidth = 4 view.isUserInteractionEnabled = true view.backgroundColor = .red return view }() override func viewDidLoad() { super.viewDidLoad() self.view.addSubview(button) self.view.addSubview(littleView) littleView.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))) button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) NSLayoutConstraint.activate([ button.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor), button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor), littleView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1/5), littleView.widthAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1/3), ]) } override func viewDidLayoutSubviews() { littleView.frame = CGRect(x: 0, y: 0, width: littleView.frame.width, height: littleView.frame.height) } override func viewWillLayoutSubviews() { littleView.frame = CGRect(x: 0, y: 0, width: littleView.frame.width, height: littleView.frame.height) } @objc private func buttonTapped() { button.setImage(UIImage(systemName: isTapped ? "play.slash" : "play"), for: .normal) self.view.layoutIfNeeded() isTapped.toggle() print("Button tapped") } @objc private func handlePan(_ gesture: UIPanGestureRecognizer) { guard let viewToMove = gesture.view else { return } if gesture.state == .began || gesture.state == .changed { let translation = gesture.translation(in: view) let newX = max(0, min(view.frame.width - viewToMove.frame.width, viewToMove.frame.origin.x + translation.x)) let newY = max(0, min((view.frame.height - viewToMove.frame.height), viewToMove.frame.origin.y + translation.y)) viewToMove.frame.origin = CGPoint(x: newX, y: newY) gesture.setTranslation(CGPoint.zero, in: view) } } } Github link
1
0
593
Aug ’23
UIManagedDocument hangs the main thread
Under certain circumstances UIManagedDocument blocks the main thread: I encountered this with situation when two different external writers in quick succession request coordinated write on the document’s file. After the 1st writer finishes its work, UIManagedDocument starts the revert process, and if at the same time the 2nd writer requests coordinated write, it seems that the coordinator allows the 2nd writer to begin, but then everything hangs: on Main thread UIManagedDocument waits for coordinated read, while the 2nd writer never reaches its writer block. The problem occurs only on iOS, I get it on iPad. I have a sample project, one of the tests result, spindump from the failed test: https://www.dropbox.com/scl/fo/qm40ano3kz15lucjj1zx3/h?rlkey=2029ge5moou7ghaqqnklsp7us&dl=0 Open the project and start the test on iPad (there is only one test: testExternalWrite), the problem may occur inconsistently. I submitted a report in Feedback Assistant like a month ago—no reaction. If somebody has time to take a look and say something, thank you very much!
2
0
490
Aug ’23
Using LazyHGrid/ LazyHStack inside Custom ScrollView. Lazy Nature doesn't work.
Can anybody tell me how can i set offset in a ScrollView?I have checked ScrollTo(), which scroll to index wise. But I want to move scrollview with offset. I have also checked Custom ScrollView( from UIScrollView) which can be used to set and get offset, but LazyHStack/LazyHGrid inside the custom Scrollview causes problem as their lazy nature doesn't work. Can anybody help me with this issue? Custom ScrollView Code Link : https://gist.github.com/jfuellert/67e91df63394d7c9b713419ed8e2beb7
0
0
232
Aug ’23
Xcode Previews for UIKit not working
I am having an issue when previewing a UIKit ViewController. I am developing my app inside Pods framework which then I import and use in scene/app delegate. I tried to use UIKit to have SwiftUI previews. I conformed to UIViewRepresentable protocol and made a struct that conforms to PreviewProvider where I returned the current controller as some View. I have many external dependencies like Moya, Alamofire, SnapKit... I am building my components in Pods project. Which I import than into scene/app delegate to start the app. I am getting the error: "Cannot preview in this file; Unexpected error occurred". I went online and found some people saying that I need to disable Automatically Refresh Canvas setting. But it still doesn't work. I am then getting an error: "Cannot preview in this file; Update failed". I attached a file with a generated report from the error. I also cleaned the build folder and restarted my Mac. I am using Macbook Pro M2. If I run UIKit previews in a new project it works. But I need it to be able to run in my current project. https://www.notion.so/Xcode-Previews-UIKit-Error-Report-ba5ec69080f34cb09c6f93c6cd0131d7?pvs=4
2
0
1.6k
Aug ’23
SwiftUI button added inside uikit view using hosting controller is not triggering a action
When i am using a swiftUI's button with the help of a UIHostingController inside a UIKit based view , Swift UI view with button : - @State var uTitle:String! @State var uFrame:CGRect! var body: some View { Button(action: { self.ButtonAction(pId: uId) }) { Text(uTitle) } } func ButtonAction (pId:Int) { print ("Hello world !!!!!") } } If i use above SwiftUIButton this way ( Adding button.frame.size ) :- let button:UIView! button = UIHostingController(rootView: SwiftUIButton (uTitle: "Button title")).view button.frame.origin = CGPoint(x: 50, y: 50) button.frame.size = CGSize(width: 150, height: 50) parentview.addSubview(button) Button click action works fine. But if i use button this way (not adding width height after intantiation of UIHostingController ,instead adding width height inside SwiftUIButton using .frame(widht: ,height:)) let button:UIView! button = UIHostingController(rootView: SwiftUIButton (uTitle: "Button title")).view button.frame.origin = CGPoint(x: 50, y: 50) // Removed frame.size parentview.addSubview(button) @State var uTitle:String! @State var uFrame:CGRect! var body: some View { Button(action: { self.ButtonAction(pId: uId) }) { Text(uTitle) // Added .frame property .frame(width:150,height:50) } } func ButtonAction (pId:Int) { print ("Hello world !!!!!") } } Action is not triggering. What could be the issue?
1
0
956
Aug ’23
Alpha Value of UIButton set in a storyboard is reset on Light/Dark Mode Transition
Hello fellow developers, I've encountered a peculiar issue in iOS 16 that I wanted to bring to light and see if anyone else has experienced the same. Issue Description: When designing a user interface in a storyboard, if I set the alpha value of a UI component (e.g., UIView, UIButton) to 0.0 within the storyboard, and then programmatically change that alpha value to 1.0 during runtime, the alpha value unexpectedly reverts back to its original storyboard value (0.0) when the device transitions between light and dark modes. Steps to Reproduce: Create a UI component in a storyboard and set its alpha to 0.0. Programmatically change the alpha value of the component to 1.0 during runtime. Trigger a light/dark mode transition on the device. Observe that the component's alpha value reverts to 0.0. Additional Observations: This behavior seems as if the UIView is being reloaded from the storyboard during the mode transition. However, breakpoints set in viewDidLoad() and loadView() are not triggered during the mode change, indicating that the views are not being reloaded in the traditional sense. This issue was observed in iOS 16, but it's unclear if it's present in previous iOS versions. Has anyone else experienced this behavior? If so, are there any known workarounds or fixes? It's crucial for ensuring a consistent user experience across mode transitions. Thank you for your insights and assistance!
6
0
1k
Aug ’23
How to change the color of navigation bar's button for title menu
I have not found any documentation for how to change the color or tint of the button with the little chevron looking down next to a navigation bar's title. The button that pops open the menu with the "Rename" and other actions you assign via the navigation item's titleMenuProvider. Is it even possible to change it? I have my navigation item's style set to .editor if it makes any difference. Thanks!
1
0
334
Aug ’23