Hi everyone,
I've been testing the requestGeometryUpdate() API in iOS, and I noticed something unexpected: it allows orientation changes even when the device’s orientation lock is enabled.
Test Setup:
Use requestGeometryUpdate() in a SwiftUI sample app to toggle between portrait and landscape (code below).
Manually enable orientation lock in Control Center.
Press a button to request an orientation change in sample app.
Result: The orientation changes even when orientation lock is ON, which seems to override the expected system behavior.
Questions:
Is this intended behavior?
Is there official documentation confirming whether this is expected? I haven’t found anything in Apple’s Human Interface Guidelines (HIG) or UIKit documentation that explicitly states this.
Since this behavior affects a system-wide user setting, could using requestGeometryUpdate() in this way lead to App Store rejection?
Since Apple has historically enforced respecting user settings, I want to clarify whether this approach is compliant.
Would love any official guidance or insights from Apple engineers.
Thanks!
struct ContentView: View {
@State private var isLandscape = false // Track current orientation state
var body: some View {
VStack {
Text("Orientation Test")
.font(.title)
.padding()
Button(action: toggleOrientation) {
Text(isLandscape ? "Switch to Portrait" : "Switch to Landscape")
.bold()
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
}
}
private func toggleOrientation() {
guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
print("No valid window scene found")
return
}
// Toggle between portrait and landscape
let newOrientation: UIInterfaceOrientationMask = isLandscape ? .portrait : .landscapeRight
let geometryPreferences = UIWindowScene.GeometryPreferences.iOS(interfaceOrientations: newOrientation)
scene.requestGeometryUpdate(geometryPreferences) { error in
print("Failed to change orientation: \(error.localizedDescription)")
}
self.isLandscape.toggle()
}
}
UIKit
RSS for tagConstruct and manage graphical, event-driven user interfaces for iOS or tvOS apps using UIKit.
Post
Replies
Boosts
Views
Activity
when I input something in UITextField or UITextView, I got the error below:*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[NSXPCEncoder _checkObject:]: This coder only encodes objects that adopt NSSecureCoding (object is of class 'NSMallocBlock').'
This pertains to iPad apps and UITabbarController in UIKit.
Our internal app for employees utilizes UITabbarController displayed at the bottom of the screen. Users prefer to maintain consistency with it being at the bottom. It becomes challenging to argue against this when users point out the iPhone version displaying it "correctly" at the bottom. My response is to trust Apple's design team to keep it at the top.
One workaround is to develop the app using the previous Xcode version, version 15 (via Xcode Cloud), targeting padOS17. This ensures the tab bar is shown at the bottom of the screen. However, this approach has its drawbacks: Apple may not support it in the future, leading to missed secure updates for the app, among other issues.
Exploring the UITabbarController mode appears to be the solution I am seeking. To quote the documentation "on iPad, If the tabs array contains one or more UITabGroup items, the system displays the content as either a tab bar or a sidebar, depending on the context. Otherwise, it only displays the content only as a tab bar.". The part "displays the content only as a tab bar." made think this is BAU:
class ViewController: UITabBarController {
override func viewDidLoad() {
super.viewDidLoad()
self.mode = .tabBar
}
}
Unfortunately, this does not resolve the issue.
Is there an API method that can force the tabbar to its previous bottom position?
The app uses multiple windows. When we split a window to launch another instance, the tab bar appears at the bottom. This behavior seems tied to the form factor—or potentially to how many items are in the tab bar.
We could build a custom tab bar to override this, but that goes against my “don’t reinvent the wheel” principle.
Any comments we welcome and thank you for reading this (to the end)
Theo
I have a SwiftUI View I've introduced to a UIKit app, using UIHostingController. The UIView instance that contains the SwiftUI view is animated using auto layout constraints. In this code block, when a view controller's viewDidAppear method I'm creating the hosting controller and adding its view as a subview of this view controller's view, in addition to doing the Container View Controller dance.
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let hostingViewController = UIHostingController(rootView: TestView())
hostingViewController.view.translatesAutoresizingMaskIntoConstraints = false
addChild(hostingViewController)
view.addSubview(hostingViewController.view)
let centerXConstraint = hostingViewController.view.centerXAnchor.constraint(equalTo: view.centerXAnchor)
let topConstraint = hostingViewController.view.topAnchor.constraint(equalTo: view.topAnchor)
widthConstraint = hostingViewController.view.widthAnchor.constraint(equalToConstant: 361)
heightConstraint = hostingViewController.view.heightAnchor.constraint(equalToConstant: 342)
NSLayoutConstraint.activate([centerXConstraint, topConstraint, widthConstraint, heightConstraint])
hostingViewController.didMove(toParent: self)
self.hostingViewController = hostingViewController
}
I add a button to the UI which will scale the UIHostingViewController by adjusting its height and width constraints. When it's tapped, this action method runs.
@IBAction func animate(_ sender: Any) {
widthConstraint.constant = 120.3
heightConstraint.constant = 114.0
UIView.animate(withDuration: 0.5) {
self.view.layoutIfNeeded()
}
}
The problem is, the SwiftUI view's contents "jump" at the start of the animation to the final height, then animate into place. I see this both using UIView.animate the UIKit way, or creating a SwiftUI animation and calling `UIView.
What else do I need to add to make this animate smoothly?
@IBOutlet weak var surnameTextField: UITextField!
surnameTextField.backgroundColor = UIColor.clear
surnameTextField.tintColor = .white
surnameTextField.textColor = .white
surnameTextField.attributedPlaceholder = NSAttributedString(string: surnameTextField.placeholder!, attributes: [NSAttributedString.Key.foregroundColor: UIColor(white: 1.0, alpha: 0.6)])
let bottomLayersurname = CALayer()
bottomLayersurname.frame = CGRect(x: 0, y: 29, width:1000, height: 0.6)
bottomLayersurname.backgroundColor = UIColor.lightGray.cgColor
surnameTextField.layer.addSublayer(bottomLayersurname)
In the header for UIViewController, the method dismissViewControllerAnimated is declared like this:
- (void)dismissViewControllerAnimated: (BOOL)flag completion: (void (^ __nullable)(void))completion NS_SWIFT_DISABLE_ASYNC API_AVAILABLE(ios(5.0));
NS_SWIFT_DISABLE_ASYNC means that there's no async version exposed like there would normally be of a method that exposes a completion handler. Why is this? And is it unwise / unsafe for me to make my own async version of it using a continuation?
My use case is that I want a method that will sequentially dismiss all view controllers presented by a root view controller. So I could have this extension on UIViewController:
extension UIViewController {
func dismissAsync(animated: Bool) async {
await withCheckedContinuation { continuation in
self.dismiss(animated: animated) {
continuation.resume()
}
}
}
func dismissPresentedViewControllers() async {
while self.topPresentedViewController != self {
await self.topPresentedViewController.dismissAsync(animated: true)
}
}
var topPresentedViewController: UIViewController {
var result = self
while result.presentedViewController != nil {
result = result.presentedViewController!
}
return result
}
in iOS, user can set focus on UItextField and tapping a key in the virtual keyboard updates the text in the textfield. This user action causes the relevant delegates of UITextFieldDelegate to get invoked, i.e the handlers associated with action of user entering some text in the textfield.
I m trying to simulate this user action where I am trying to do this programatically. I want to simulate it in a way such that all the handlers/listeners which otherwise would have been invoked as a result of user typing in the textfield should also get invoked now when i am trying to do it programatically. I have a specific usecase of this in my application.
Below is how I m performing this simulation.
I m manually updating the text field associated(UITextField.text) and updating its value.
And then I m invoking the delegate manually as textField.delegate?.textField?(textField, shouldChangeCharactersIn: nsRange, replacementString: replacementString)
I wanted to know If this is the right way to do this. Is there something better available that can be used, such that simulation has the same affect as the user performing the update?
I want SensorKit data for research purposes in my current application. I have applied for and received permission from Apple to access SensorKit data.
During implementation, I encountered an issue in which no data was being retrieved despite granting all the necessary permissions.
I am using did CompleteFetch & didFetchResult delegate methods for retrieving data from Sensorkit. CompleteFetch method calls but where I can find different event data like Device usage, Ambient Light, etc? & didFetchResult method does not call.
Methods I am using:
1. func sensorReader(_ reader: SRSensorReader, didCompleteFetch fetchRequest: SRFetchRequest)
2. func sensorReader(_ reader: SRSensorReader, fetching fetchRequest: SRFetchRequest, didFetchResult result: SRFetchResult<AnyObject>) -> Bool
Could anyone please assist me in resolving this issue? Any guidance or troubleshooting steps would be greatly appreciated.
I wanted to perform simulation in my application as a self tour guide for my user. For this I want to programatically simulate various user interaction events like button click, keypress event in the UITextField or moving the cursor around in the textField. These are only few examples to state, it can be any user interaction event or other events.
I wanted to know what is the apple recommendation on how should these simulations be performed? Is there something that apple offers like creating an event which can be directly executed for simulations. Is there some library available for this purpose?
I writing swift code to change the app icon using setAlternateIconName and flutter MethodChannel to invoke swift.
UIApplication.shared.setAlternateIconName(iconName) { error in
if let error = error {
print("Error setting alternate icon: \(error.localizedDescription)")
result(FlutterError(code: "ICON_CHANGE_ERROR", message: error.localizedDescription, details: nil)) // Send error back to Flutter
} else {
print("App icon changed successfully!")
result(nil) // Success!
}
}
But I got an error message the requested operation couldn't be completed because the feature is not supported when using it on iOS 17+.
So, Is setAlternateIconName still available?
PS. In XCode, the code hinting shows that setAlternateIconName is still not deprecated.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
do {
let shapeLayer = CAShapeLayer()
shapeLayer.frame = CGRect(x: 50, y: 100, width: 200, height: 108)
let path = UIBezierPath(roundedRect: shapeLayer.bounds, cornerRadius: 36)
shapeLayer.path = path.cgPath
shapeLayer.fillColor = UIColor.orange.cgColor
view.layer.addSublayer(shapeLayer)
}
do {
let layer = CALayer()
layer.backgroundColor = UIColor.blue.cgColor
layer.cornerRadius = 36
layer.frame = CGRect(x: 50, y: 300, width: 200, height: 108)
view.layer.addSublayer(layer)
}
}
}
The corner radius is set to 36 through CAShapeLayer, but the actual effect is larger than 36, close to half of the height.
Setting it through CALayer is fine
Can anyone explain it to me? Thank you
I'm having this problem, with this code:
let docPicker = UIDocumentPickerViewController(forOpeningContentTypes: [
.pdf
])
docPicker.delegate = self
docPicker.modalPresentationStyle = .currentContext
view.window?.rootViewController?.present(docPicker, animated: true, completion: nil)
but then when I open the simulator and click the button that calls to the method that has this code...
Cannot pick the pdf document.
Testing in browserstack with real devices is working, but it's a very slow process, why I cannot use simulators to make work this?
I found a memory leak in tvOS 17.4, but it's not happening in tvOS 18.0
here is the code flow
1.I have controller inside which I have tableView which in turn contains a collectionview
here I have passed self to tableViewcell as delegate and then from tableview cell I have passed self again as delegate to collectionViewcell, but memory is not released, because self is retained
"I have passed self as weak every where still memory leak is happening only in tvOS 17.4 and below versions. but in 18.0 and above versions it's fine"
IOS 12 - 18.1.1 - objective C, Xcode 16.0
App runs on both iPhone and iPad, this issue only occurs happens on iPads. For the iPhones I am able to get a decent numeric only keyboard to display.
I pulled down NumericKeypad from GitHub and used that a model on how to implement a custom keypad.
In the inputView of the delegate, a new custom text field is create and then assigned a delegate and other properties then it returns the view to the main ViewController. When the ViewControllers and the correct text field is entered my custom keyboard display and the buttons respond but nothing is displayed in the text field. This has worked for years and all of the sudden it stopped.
The original project for the example 10 key custom keyboard builds and when loaded that works on the iPad. If I comment out condition to only execute if running on an iPad and test with an iPhone the keyboards works.
It is only on a iPad that this happens.
This is the cod that creates creates the keyboard from a .xib file. I am using a storyboard for the main app.
#import "Numeric10KeyTextField.h"
#import "Numeric10KeyViewController.h"
@implementation Numeric10KeyTextField
(UIView *)inputView {
UIView *view = nil;
Numeric10KeyViewController *numVC;
// Add hook here for iPhone or other devices if needed but now return nil if iPhone so it uses the default
// if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
numVC = [[Numeric10KeyViewController alloc] initWithNibName:@"Numeric10Key" bundle:nil];
[numVC setActionSubviews:numVC.view];
numVC.delegate = self.numeric10KeyDelegate;
numVC.numpadTextField = self;
view = numVC.view;
// }
return view;
}
@end
I create a notification with an image attachment:
let center = UNUserNotificationCenter.current()
center.delegate = self
let content = UNMutableNotificationContent()
// some more stuff…
let paths = NSSearchPathForDirectoriesInDomains(
FileManager.SearchPathDirectory.documentDirectory,
FileManager.SearchPathDomainMask.userDomainMask, true)
let documentsDirectory = paths[0] as NSString
let fileExtPNG = "#" + "\(imageName)" + " photo.png"
let fileNamePNG = documentsDirectory.appendingPathComponent(fileExtPNG) as String
url = URL(fileURLWithPath: fileNamePNG)
let attachment = try UNNotificationAttachment(identifier: "Image", url: url, options: nil)
content.attachments = [attachment]
I then add the request:
let request = UNNotificationRequest(identifier:requestIdentifier, content: content, trigger: nil)
center.removePendingNotificationRequests(withIdentifiers: [requestIdentifier])
center.add(request) {(error) in }
Problem: when I later test (once notification has been registered), the file do not exist anymore at the url.
I've commented out the add request to confirm.
I have a work around, by creating a temporary copy of the file at the URL and pass it in the attachment.
Then, everything works fine and the copy is deleted.
But that's a bit bizarre. What am I missing here ?
Hello!
I’m experiencing a crash in my iOS/iPadOS app related to a CALayer rendering process. The crash occurs when attempting to render a UIImage on a background thread. The crashes are occurring in our production app, and while we can monitor them through Crashlytics, we are unable to reproduce the issue in our development environment.
Relevant Code
I have a custom view controller that handles rendering CALayers onto images. This method creates a CALayer on the main thread and then starts a detached task to render this CALayer into a UIImage. The whole idea is learnt from this StackOverflow post: https://stackoverflow.com/a/77834613/9202699
Here are key parts of my implementation:
class MyViewController: UIViewController {
@MainActor
func renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) async -> UIImage? {
// Create CALayer and add it to the view.
CATransaction.begin()
let customLayer = MyDrawingLayer()
customLayer.setupContent(itemsToDraw: itemsToDraw)
// Position the frame off-screen to it hidden.
customLayer.frame = CGRect(
origin: CGPoint(x: -100 - size.width, y: -100 - size.height),
size: size)
customLayer.masksToBounds = true
customLayer.drawsAsynchronously = true
view.layer.addSublayer(customLayer)
CATransaction.commit()
// Render CALayer to UIImage in background thread.
let image = await Task.detached {
customLayer.setNeedsDisplay()
let renderer = UIGraphicsImageRenderer(size: size)
let image = renderer.image { // CRASH happens on this line
let cgContext = $0.cgContext
cgContext.saveGState()
cgContext.concatenate(transform)
customLayer.render(in: cgContext)
cgContext.restoreGState()
}
return image
}.value
// Remove the CALayer from the view.
CATransaction.begin()
customLayer.removeFromSuperlayer()
CATransaction.commit()
return image
}
}
class MyDrawingLayer: CALayer {
var itemsToDraw: [MyDrawingItem] = []
func setupContent(itemsToDraw: [MyDrawingItem]) {
self.itemsToDraw = itemsToDraw
}
override func draw(in ctx: CGContext) {
for item in itemsToDraw {
// Render the item to the context (example pseudo-code).
// All items are thread-safe to use.
// Things to draw may include CGPath, CGImages, UIImages, NSAttributedString, etc.
item.draw(in: ctx)
}
}
}
Crash Log
The crash occurs at the following location:
Crashed: com.apple.root.default-qos.cooperative
0 MyApp 0x5cb300 closure #1 in closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 4313002752 (<compiler-generated>:4313002752)
1 MyApp 0x5cb300 closure #1 in closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 4313002752 (<compiler-generated>:4313002752)
2 MyApp 0x1a4578 AnyModifier.modified(for:) + 4308649336 (<compiler-generated>:4308649336)
3 MyApp 0x7b4e64 thunk for @escaping @callee_guaranteed (@guaranteed UIGraphicsPDFRendererContext) -> () + 4315008612 (<compiler-generated>:4315008612)
4 UIKitCore 0x1489c0 -[UIGraphicsRenderer runDrawingActions:completionActions:format:error:] + 324
5 UIKitCore 0x14884c -[UIGraphicsRenderer runDrawingActions:completionActions:error:] + 92
6 UIKitCore 0x148778 -[UIGraphicsImageRenderer imageWithActions:] + 184
7 MyApp 0x5cb1c0 closure #1 in MyViewController.renderToUIImage(size: CGSize, itemsToDraw: [MyDrawingItem], transform: CGAffineTransform) + 100 (FileName.swift:100)
8 libswift_Concurrency.dylib 0x60f5c swift::runJobInEstablishedExecutorContext(swift::Job*) + 252
9 libswift_Concurrency.dylib 0x62514 swift_job_runImpl(swift::Job*, swift::SerialExecutorRef) + 144
10 libdispatch.dylib 0x15ec0 _dispatch_root_queue_drain + 392
11 libdispatch.dylib 0x166c4 _dispatch_worker_thread2 + 156
12 libsystem_pthread.dylib 0x3644 _pthread_wqthread + 228
13 libsystem_pthread.dylib 0x1474 start_wqthread + 8
Questions
Is it safe to run UIGraphicsImageRenderer.image on the background thread?
Given that I want to leverage GPU rendering, what are some best practices for rendering images off the main thread while ensuring stability?
Are there alternatives to using UIGraphicsImageRenderer for background rendering that can still take advantage of GPU rendering?
It is particularly interesting that the crash logs indicate the error may be related to UIGraphicsPDFRendererContext (crash log line number 3). It would be very helpful if someone could explain the connection between starting and drawing on a UIGraphicsImageRenderer and UIGraphicsPDFRendererContext.
Any insights or guidance on this issue would be greatly appreciated. Thanks!!!
When picking a photo in the gallery, whatever the orientation of the original image, size is always as landscape
if let image = info[convertFromUIImagePickerControllerInfoKey(UIImagePickerController.InfoKey.editedImage)] as? UIImage {
print("picked original", image.size)
For a portrait photo:
picked original (1122.0, 932.0)
For a landscape:
picked original (1124.0, 844.0)
What am I missing ?
I have a setup:
Collection view with compositional layout
a self sizing cell inside
a subview inside the cell
and unrelated view outside the collection view
I would like to:
modify the layout (constraints) of the cell inside the collection view with UIView.animate
trigger an animated layout update of collection view
synchronize the position of an unrelated view to the position of one of the subviews of a collection view cell
What I tried:
UIView.animate(withDuration: 0.25) {
cellViewReference.updateState(state: state, animated: false)
collectionView.collectionViewLayout.invalidateLayout()
collectionView.layoutIfNeeded()
someOtherViewOutsideCollectionView.center = cellViewReference.getPositionOfThatOneViewInWindowCoordinateSystem()
}
What I'm expecting:
after invalidateLayout, the layout update of the collection view is merely scheduled, but not yet performed
layoutIfNeeded forces an update on the collectionViewLayout + update on the frames of the views inside the UICollectionViewCells
all the frames become correct to what they will look like after the animation is performed
I call getPositionOfThatOneViewInWindowCoordinateSystem and it gives me the position of the view after the uicollectionview AND the cell's layout has updated
What happens instead:
getPositionOfThatOneViewInWindowCoordinateSystem returns me an old value
I am observing that the bounds of the cell didn't actually change during layoutIfNeeded
And moreover, the bounds change without animation, instantly
Question:
how to animate self sizing cell size change due relayout
how to synchronize outside views with collection views
When pushing a page in the navigation, changing the state of interactivePopGestureRecognizer causes the page to freeze.
Just like this:
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
CGFloat red = (arc4random_uniform(256) / 255.0);
CGFloat green = (arc4random_uniform(256) / 255.0);
CGFloat blue = (arc4random_uniform(256) / 255.0);
CGFloat alpha = 1.0; //
self.view.backgroundColor = [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
btn.frame = CGRectMake(0, 0, 100, 44);
btn.backgroundColor = [UIColor redColor];
btn.center = self.view.center;
[btn setTitle:@"push click" forState:UIControlStateNormal];
[btn addTarget:self action:@selector(click:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
- (void)click:(id)sender {
[self.navigationController pushViewController:[ViewController new] animated:YES];
}
- (void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
self.navigationController.interactivePopGestureRecognizer.enabled = NO;
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
self.navigationController.interactivePopGestureRecognizer.enabled = YES;
}
@end
Modern collection views use UICollectionViewDiffableDataSource with UICollectionView.CellRegistration and UICollectionView.dequeueConfiguredReusableCell(registration:indexPath:item).
There are runtime crashes when passing nil as argument for the item parameter. There's no clear documentation on whether optional items are allowed or not.
The function signature in Swift is:
@MainActor @preconcurrency func dequeueConfiguredReusableCell<Cell, Item>(using registration: UICollectionView.CellRegistration<Cell, Item>, for indexPath: IndexPath, item: Item?) -> Cell where Cell : UICollectionViewCell
Given the Item? type one would assume Optionals are allowed.
In Objective-C the signature is:
- (__kindof UICollectionViewCell *)dequeueConfiguredReusableCellWithRegistration:(UICollectionViewCellRegistration *)registration forIndexPath:(NSIndexPath *)indexPath item:(id)item;
I'm not sure, if there's implicit nullability bridging to the Swift API or if the Objective-C files has some explicit nullability annotation.
The crash is due to a swift_dynamicCast failing with:
Could not cast value of type '__SwiftNull' (0x10b1c4dd0) to 'Item' (0x10d6086e0).
It's possible to workaround this by making a custom Optional type like
enum MyOptional<T> {
case nothing
case something(T)
}
and then wrapping and unwrapping Item? to MyOptional<Item>. But this feels like unnecessary boilerplate.
With the current situation it's easy to ship an app where everything seems to work, but in production only certain edge cases cause nil values being used and then crashing the app.
Please clarify the allowed arguments / types for the dequeueConfiguredReusableCell function.
Either Optionals should be supported and not crash at runtime or the signatures should be changed so there's a compile time error, when trying to use an Item?.
Feedback: FB16494078