Construct 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

Moving SceneDelegate to a different target
I have a SwiftUI project which has the following hierarchy: IOSSceneDelegate (App target) - depends on EntryPoint and Presentation static libs. Presentation (Static library) - Depends on EntryPoint static lib. Contains UI related logic and updates the UI after querying the data layer. EntryPoint (Static library) - Contains the entry point, AppDelegate (for its lifecycle aspects) etc. I've only listed the relevant targets here. SceneDelegate was initially present in EntryPoint library, because the AppDelegate references it when a scene is created. public func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Set the SceneDelegate dynamically let sceneConfig: UISceneConfiguration = UISceneConfiguration(name: "mainWindow", sessionRole: connectingSceneSession.role) sceneConfig.delegateClass = SceneDelegate.self return sceneConfig } The intent is to move the SceneDelegate to the Presentation library. When moved, the EntryPoint library fails to compile because it's referencing the SceneDelegate (as shown above). To remove this reference, I tried to set up the SceneDelegate in the old way - In the info.plist file, mention a SceneConfiguration and set the SceneDelegate in Presentation. // In the Info.plist file <key>UIApplicationSceneManifest</key> <dict> <key>UIApplicationSupportsMultipleScenes</key> <true/> <key>UISceneConfigurations</key> <dict> <key>UIWindowSceneSessionRoleApplication</key> <array> <dict> <key>UISceneConfigurationName</key> <string>Default Configuration</string> <key>UISceneDelegateClassName</key> <string>Presentation.SceneDelegate</string> </dict> </array> </dict> </dict> // In the AppDelegate public func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { // Refer to a static UISceneconfiguration listed in the info.plist file return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) } As shown above, the Presentation.SceneDelegate is referred in the Info.plist file and the reference is removed from the AppDelegate (in EntryPoint library). The app target compiles, but when I run it, the SceneDelegate is not invoked. None of the methods from the SceneDelegate (scene(_:willConnectTo:options:), sceneDidDisconnect(_:), sceneDidEnterBackground(_:) etc.) are invoked. I only get the AppDelegate logs. It seems like the Configuration is ignored because it was incorrect. Any thoughts? Is it possible to move the SceneDelegate in this situation?
0
1
362
Feb ’25
EntityAction for MaterialBaseTint - incorrect colours
Hello, I'm writing an EntityAction that animates a material base tint between two different colours. However, the colour that is being actually set differs in RGB values from that requested. For example, trying to set an end target of R0.5, G0.5, B0.5, results in a value of R0.735357, G0.735357, B0.735357. I can also see during the animation cycle that intermediate actual tint values are also incorrect, versus those being set. My understanding is the the values of material base colour are passed as a SIMD4. Therefore I have a couple of helper extensions to convert a UIColor into this format and mix between two colours. Note however, I don't think the issue is with this functions - even if their outputs are wrong, the final value of the base tint doesn't match the value being set. I wondered if this was a colour space issue? import simd import RealityKit import UIKit typealias Float4 = SIMD4<Float> extension Float4 { func mixedWith(_ value: Float4, by mix: Float) -> Float4 { Float4( simd_mix(x, value.x, mix), simd_mix(y, value.y, mix), simd_mix(z, value.z, mix), simd_mix(w, value.w, mix) ) } } extension UIColor { var float4: Float4 { var r: CGFloat = 0.0 var g: CGFloat = 0.0 var b: CGFloat = 0.0 var a: CGFloat = 0.0 getRed(&r, green: &g, blue: &b, alpha: &a) return Float4(Float(r), Float(g), Float(b), Float(a)) } } struct ColourAction: EntityAction { let startColour: SIMD4<Float> let targetColour: SIMD4<Float> var animatedValueType: (any AnimatableData.Type)? { SIMD4<Float>.self } init(startColour: UIColor, targetColour: UIColor) { self.startColour = startColour.float4 self.targetColour = targetColour.float4 } static func registerEntityAction() { ColourAction.subscribe(to: .updated) { event in guard let animationState = event.animationState else { return } let interpolatedColour = event.action.startColour.mixedWith(event.action.targetColour, by: Float(animationState.normalizedTime)) animationState.storeAnimatedValue(interpolatedColour) } } } extension Entity { func updateColour(from currentColour: UIColor, to targetColour: UIColor, duration: Double, endAction: @escaping (Entity) -> Void = { _ in }) { let colourAction = ColourAction(startColour: currentColour, targetColour: targetColour, endedAction: endAction) if let colourAnimation = try? AnimationResource.makeActionAnimation(for: colourAction, duration: duration, bindTarget: .material(0).baseColorTint) { playAnimation(colourAnimation) } } } The EntityAction can only be applied to an entity with a ModelComponent (because of the material), so it can be called like so: guard let modelComponent = entity.components[ModelComponent.self], let material = modelComponent.materials.first as? PhysicallyBasedMaterial else { return } let currentColour = material.baseColor.tint let targetColour = UIColor(_colorLiteralRed: 0.5, green: 0.5, blue: 0.5, alpha: 1.0) entity.updateColour(from:currentColour, to: targetColour, duration: 2)
1
0
532
Feb ’25
Performing simulations in the UI elements in uikit
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?
Topic: UI Frameworks SubTopic: UIKit Tags:
2
0
282
Feb ’25
ContactAccessPicker crashing issue
Given Apple's new .limited contact authorization introduced in ios18, I want to be able to present the ContactAccessPicker directly from my app, via ionic capacitor. I present the .contactAccessPicker view via a UIHostingController, and I manage the view controller's dismissal accordingly when the ContactAccessPicker completes and is no longer presented. Bug: After a few searches or interactions with the Contact Access Picker (ex. searching, selecting contacts, clicking the "show selected" button), the contact access picker crashes and the overlay remains. Any interaction with my app is then blocked because I can't detect that the contact access picker has disappeared when it crashes so I can't dismiss the viewController. Is there a way for me to prevent the contact access picker from crashing, and how can I detect if it does crash, so I can at least dismiss the view controller if that happens? struct ContactAccessPickerView: View { @Binding var isPresented: Bool let completion: @MainActor ([String]) -> Void var body: some View { Group { if #available(iOS 18.0, *) { Color.clear .contactAccessPicker(isPresented: $isPresented) { result in Task { @MainActor in completion(result) } } } else { } } } } @objc func selectMoreContacts(_ call: CAPPluginCall) { guard isContactsPermissionGranted() else { call.resolve(["success": false]) return } // Save the call to ensure it's available until we finish self.bridge?.saveCall(call) DispatchQueue.main.async { [weak self] in guard let self = self else { return } var isPresented = true let picker = ContactAccessPickerView(isPresented: .init(get: { isPresented }, set: { isPresented = $0 })) { contacts in call.resolve(["success": true]) self.dismissAndCleanup(call) } let hostingController = UIHostingController(rootView: picker) hostingController.modalPresentationStyle = .overFullScreen self.bridge?.viewController?.present(hostingController, animated: true) } }
1
2
443
Feb ’25
Setting rounded corners via CAShapeLayer.path looks problematic
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
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
268
Feb ’25
UIDocumentPickerViewController of type pdf cannot pick pdf in simulator
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?
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
276
Feb ’25
Memory Leak in Apple TV(tvOS 17.4)
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"
1
0
327
Feb ’25
iPAD custom in app keyboard stopped responding
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
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
426
Feb ’25
swiftui fileimporter inside UIHostingController
I'm working on an old iOS app that started with objective-C + UIKit and has being migrated to Swift + SwiftUI. Currently its code is mostly Swift + SwiftUI but it has still some objective-C and some UIKit ViewControllers. One of the SwiftUI views uses fileImporter to open Files App and select a file from the device. This has been working well until iOS 18 is launched. With iOS 18 the file picker is not launching correctly and is frozen in every simulator (the unique real device I've could test with iOS 18 seemed to work correctly). I managed to clone my project and leave it with the minimal amount of files to reproduce this error. This is the code: AppDelegate.h #import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> {} @property (strong, nonatomic) UIWindow *window; @end AppDelegate.m #import "AppDelegate.h" #import "MyApp-Swift.h" @interface AppDelegate () @end @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; FirstViewBuilder *viewBuilder = [[FirstViewBuilder alloc] init]; [viewBuilder show]; return YES; } @end FirstViewBuilder.swift import SwiftUI @objc class FirstViewBuilder: NSObject { private var view: UIHostingController<FirstView> @objc override init() { self.view = MyHostingController(rootView: FirstView()) } @objc func show() { let app = UIApplication.shared.delegate as? AppDelegate let window = app?.window window?.backgroundColor = .white // Use navigationController or view directly depending on use window?.rootViewController = view } } FirstView.swift import SwiftUI struct FirstView: View { @State var hasToOpenFilesApp = false var body: some View { VStack(alignment: .leading, spacing: 0) { Button("Open Files app") { hasToOpenFilesApp = true }.fileImporter(isPresented: $hasToOpenFilesApp, allowedContentTypes: [.text]) { result in switch result { case .success(let url): print(url.debugDescription) case .failure(let error): print(error.localizedDescription) } } } } } And finally, MyHostingController import SwiftUI class MyHostingController<Content>: UIHostingController<Content> where Content: View { override init(rootView: Content) { super.init(rootView: rootView) } @objc required dynamic init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } override func viewDidLoad() { super.viewDidLoad() navigationItem.hidesBackButton = true } } Launching this in an iPhone 13 Pro (18.2) simulator I click on Open Files App, it takes 2 seconds to open it, and it opens full screen (not like a modal). Buttons on the top are behind the status bar and buttons at the bottom are behind the Home indicator. But it's worse because the user can't interact with this view, it's frozen. I created a fresh SwiftUI project just with this unique view and the fileimport worked as expected so I thought the problem was due to embed the SwiftUI view inside the UIHostingController. So I made these modifications to the minimal project: Remove the files AppDelegate, FirstViewBuilder and MyHostingController. Create this SwiftUI App file import SwiftUI @main struct MyApp: App { var body: some Scene { WindowGroup { FirstView() } } } And again the same problem with iOS 18. But if I launch this exact project in an iPhone 13 Pro (17.4) simulator and open the files apps (now it opens almost instantly) it works OK and shows the file picker as a modal, as expected, and I can interact with it and select files. Last thing I've tried is removing LaunchScreen.xib from my project and Launch screen interface file base name key from my info.plist but the problem keeps happening. I guess it must be due to my project configuration (too old) but I have no more ideas of where to look at. The possibility of having a fresh SwiftUI project and "move" the old project to the new one could take me several weeks and I discard it by the moment. Could I use another method to select files from SwiftUI views with iOS 18?
2
0
424
Feb ’25
SwiftUI navigationDestination will make child view's stateObject init multi times with sheet modifier.
Below is my sample code. On the Home page, when I click "show sheet," the sheet page expands, and the StateObject inside the sheet is initialized once. However, when I click "show Fullscreen" and then click "show sheet" inside the fullscreen page, the sheet gets initialized twice. However, if I remove navigationDestination, this issue does not occur. This problem causes the network request in the sheet page to be triggered multiple times. Can someone tell me the reason? enum TestRouter: String, Hashable { case test var targetView: some View { Text("test") } var title: String { return "test title" } } @MainActor struct NavigationInnerView<Content>: View where Content: View { var contentView: () -> Content @MainActor public init(@ViewBuilder contentView: @escaping () -> Content) { self.contentView = contentView } var body: some View { NavigationStack() { contentView() .navigationDestination(for: TestRouter.self) { route in route.targetView } } .navigationViewStyle(StackNavigationViewStyle()) } } struct ContentView: View { @State var showFullScreen: Bool = false @State var showSheet: Bool = false var contentView: some View { VStack { VStack { Text("Home") Button { showFullScreen = true } label: { Text("show fullscreen") } Button { showSheet = true } label: { Text("show sheet ") } } } } var body: some View { NavigationInnerView { contentView .fullScreenCover(isPresented: $showFullScreen) { NavigationInnerView { FullScreenContentView() } } .sheet(isPresented: $showSheet) { NavigationInnerView { SheetContentView() } } } } } class FullScreenViewModel: ObservableObject { @Published var content: Bool = false init() { print("Full Screen ViewModel init") } } struct FullScreenContentView: View { @Environment(\.dismiss) var dismiss @State var showSheet: Bool = false @StateObject var viewModel: FullScreenViewModel = .init() init() { print("Full screen view init") } var body: some View { VStack { Text("FullScreen") Button { dismiss() }label: { Text("dismiss") } Button { showSheet = true } label: { Text("show sheet") } } .sheet(isPresented: $showSheet) { NavigationInnerView { SheetContentView() } } } } class SheetViewModel: ObservableObject { @Published var content: Bool = false init() { print("SheetViewModel init") } } struct SheetContentView: View { @Environment(\.dismiss) var dismiss @StateObject var viewModel = SheetViewModel() init() { print("sheet view init") } var body: some View { Text("Sheet") Button { dismiss() } label: { Text("dismiss") } } } #Preview { ContentView() }
3
0
330
Feb ’25
CollectionView: Sync `center.y` of UIView outside collection view and a view in a cellinside
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
Topic: UI Frameworks SubTopic: UIKit Tags:
1
0
240
Feb ’25
UICollectionView.CellRegistration and dequeueConfiguredReusableCell with nil for Item? causes runtime crash
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
Topic: UI Frameworks SubTopic: UIKit Tags:
3
1
276
Feb ’25
SFSafariViewController's preferred colors are invalidated after rotation
There are two issues about SFSafariViewController. After rotate from landscape to portrait, The topAnchor is destroyed. The specified bar tint color and control tint color are invalidated.(Returns to system color) Regarding the second issue, I’ve found a temporary workaround. Override the viewWillTransition(to:with:) and keep it empty. Don't call super.viewWillTransition(to:with:). Since UIKit is not open source, I don’t know the exact cause, but I found something that could be the key to the issue. So, I reported it to Apple Feedback Assistant. You can check the details and the sample project in the GitHub repository below. https://github.com/ueunli/SafariViewer
0
0
274
Feb ’25
iOS Architecture Research - Help a student
Hi everyone! I'm thrilled to share that I'm conducting a field research as part of my final university project, focused on iOS architecture. The goal is to dive deeper into the best practices, challenges, and trends in the iOS development world. To make this research truly impactful, I need your help! If you're an iOS developer, I’d love it if you could take a few minutes to answer a short survey. Your insights and experiences will be invaluable for my research, and I greatly appreciate your support! Here is the link: https://docs.google.com/forms/d/e/1FAIpQLSdf9cacfA7my1hnlazyl7uJraa2oTsQ7dJBWvFtZ_4vbYenRA/viewform?usp=send_form Thank you so much in advance for helping me out—feel free to share this post with others who might also be interested. Let’s build something amazing together! 💡✨
0
0
285
Feb ’25
Adding Markdown support in notes app
Hi guys, I’m making a simple note taking app and I want to support markdown functionality. I have tried to find libraries and many other GitHub repos but some of them are slow and some of them are very hard to implement and not very customizable. In WWDC 22 apple also made a markdown to html document app and I also looked at that code and it was awesome. It was fast and reliable (Apple btw). But the only problem I am facing is that the markdown text is on the left side and the output format is on the right in the form of html. I don’t want that I want both in the same line. In bear notes and things 3 you can write in markdown and you can see that it is converting in the same line. I have also attached example videos. So, I have markdown parser by apple but the only thing in the way is that it is converting it into a html document. Please help me with this. Also please look into the things 3 video they have also completely customized the text attributes selection menu. By default with UITextView we can only enable text attributes and it shows like this. By clicking more we get the complete formatting menu but not the slider menu which is more convenient. Please also help me this. I don’t know if I can provide apple file but it is from wwdc 22 supporting desktop class interaction
0
0
330
Feb ’25
Getting a file icon on iOS
Some time ago I read somewhere that one can get a file icon on iOS like this: UIDocumentInteractionController(url: url).icons.last!) but this always returns the following image for every file: Today I tried the following, which always returns nil: (try? url.resourceValues(forKeys: [.effectiveIconKey]))?.allValues[.effectiveIconKey] as? UIImage Is there any way to get a file icon on iOS? You can try the above methods in this sample app: struct ContentView: View { @State private var isPresentingFilePicker = false @State private var url: URL? var body: some View { VStack { Button("Open") { isPresentingFilePicker = true } if let url = url { Image(uiImage: UIDocumentInteractionController(url: url).icons.last!) if let image = (try? url.resourceValues(forKeys: [.effectiveIconKey]))?.allValues[.effectiveIconKey] as? UIImage { Image(uiImage: image) } else { Text("none") } } } .padding() .fileImporter(isPresented: $isPresentingFilePicker, allowedContentTypes: [.data]) { result in do { let url = try result.get() if url.startAccessingSecurityScopedResource() { self.url = url } } catch { preconditionFailure(error.localizedDescription) } } } }
2
0
422
Feb ’25