I am using LazyVStack inside a ScrollView. I understand that lazy views are rendered only when they come into view. However, I haven’t heard much about memory deallocation.
I observed that in iOS 18 and later, when scrolling up, the bottom-most views are deallocated from memory, whereas in iOS 17, they are not (Example 1).
Additionally, I noticed a similar behavior when switching views using a switch. When switching views by pressing a button, the view was intermittently deinitialized. (Example 2).
Example 1)
struct ContentView: View {
var body: some View {
ScrollView {
LazyVStack {
ForEach(0..<40) { index in
CellView(index: index)
}
}
}
.padding()
}
}
struct CellView: View {
let index: Int
@StateObject var viewModel = CellViewModel()
var body: some View {
Rectangle()
.fill(Color.accentColor)
.frame(width: 300, height: 300)
.overlay {
Text("\(index)")
}
.onAppear {
viewModel.index = index
}
}
}
class CellViewModel: ObservableObject {
@Published var index = 0
init() {
print("init")
}
deinit {
print("\(index) deinit")
}
}
#Preview {
ContentView()
}
Example 2
struct ContentView: View {
@State var index = 0
var body: some View {
LazyVStack {
Button(action: {
if index > 5 {
index = 0
} else {
index += 1
}
}) {
Text("plus index")
}
MidCellView(index: index)
}
.padding()
}
}
struct MidCellView: View {
let index: Int
var body: some View {
switch index {
case 1:
CellView(index: 1)
case 2:
CellView(index: 2)
case 3:
CellView(index: 3)
case 4:
CellView(index: 4)
default:
CellView(index: 0)
}
}
}
struct CellView: View {
let index: Int
@StateObject var viewModel = CellViewModel()
var body: some View {
Rectangle()
.fill(Color.accentColor)
.frame(width: 300, height: 300)
.overlay {
Text("\(index)")
}
.onAppear {
viewModel.index = index
}
}
}
class CellViewModel: ObservableObject {
@Published var index = 0
init() {
print("init")
}
deinit {
print("\(index) deinit")
}
}
--------------------
init
init
init
init
init
2 deinit
3 deinit
4 deinit
init
Explore the various UI frameworks available for building app interfaces. Discuss the use cases for different frameworks, share best practices, and get help with specific framework-related questions.
Post
Replies
Boosts
Views
Activity
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()
}
}
To add a background to the tab content I implement the following background, nesting another modifier equal within this one.
.background(
.background // ERROR: Ambiguous use of 'background'
.shadow(.drop(
color: .primary.opacity(0.08),
radius: 5, x: 5, y: 5)
)
.shadow(.drop(
color: .primary.opacity(0.08),
radius: 5, x: -5, y: -5)
),
in: .capsule
)
Hi,
I have noticed a major change to a SwiftUI API behavior in iOS18.4beta1 which breaks my app's functionality, and I've started hearing from users running the new beta that the app doesn't correctly work for them anymore.
The problem is with views that contain a List with multiple-selection, and the contextMenu API applied with the ‘primaryAction’ callback that is triggered when the user taps on a row. Previously, if the user tapped on a row, this callback was triggered with the 'selectedItems' showing the tapped item. With iOS18.4beta, the same callback is triggered with ‘selectedItems’ being empty.
I have the code to demonstrate the problem:
struct ListSelectionTestView: View {
@State private var items: [TimedItem] = [
TimedItem(number: 1, timestamp: "2024-11-20 10:00"),
TimedItem(number: 2, timestamp: "2024-11-20 11:00"),
TimedItem(number: 3, timestamp: "2024-11-20 12:00")
]
@State var selectedItems = Set<TimedItem.ID>()
var body: some View {
NavigationStack {
List(selection: $selectedItems) {
ForEach(items) { item in
Text("Item \(item.number) - \(item.timestamp)")
}
}
.contextMenu(forSelectionType: TimedItem.ID.self, menu: {_ in
Button(action: {
print("button called - count = \(selectedItems.count)")
}) {
Label("Add Item", systemImage: "square.and.pencil")
}
}, primaryAction: {_ in
print("primaryAction called - count = \(selectedItems.count)")
})
}
}
}
struct TimedItem: Identifiable {
let id = UUID()
let number: Int
let timestamp: String
}
#Preview {
ListSelectionTestView()
}
Running the same code on iOS18.2, and tapping on a row will print this to the console:
primaryAction called - count = 1
Running the same code on iOS18.4 beta1, and tapping on a row will print this to the console:
primaryAction called - count = 0
So users who were previously selecting an item from the row, and then seeing expected behavior with the selected item, will now suddenly tap on a row and see nothing. My app's functionality relies on the user selecting an item from a list to see another detailed view with the selected item's contents, and it doesn't work anymore.
This is a major regression issue. Please confirm and let me know. I have filed a feedback: FB16593120
I'm implementing infinite scrolling with Swift Charts where additional historical data loads when scrolling near the beginning of the dataset. However, when new data is loaded, the chart's scroll position jumps unexpectedly.
Current behavior:
Initially loads 10 data points, displaying the latest 5
When scrolling backwards with only 3 points remaining off-screen, triggers loading of 10 more historical points
After loading, the scroll position jumps to the 3rd position of the new dataset instead of maintaining the current view
Expected behavior:
Scroll position should remain stable when new data is loaded
User's current view should not change during data loading
Here's my implementation logic using some mock data:
import SwiftUI
import Charts
struct DataPoint: Identifiable {
let id = UUID()
let date: Date
let value: Double
}
class ChartViewModel: ObservableObject {
@Published var dataPoints: [DataPoint] = []
private var isLoading = false
init() {
loadMoreData()
}
func loadMoreData() {
guard !isLoading else { return }
isLoading = true
let newData = self.generateDataPoints(
endDate: self.dataPoints.first?.date ?? Date(),
count: 10
)
self.dataPoints.insert(contentsOf: newData, at: 0)
self.isLoading = false
print("\(dataPoints.count) data points.")
}
private func generateDataPoints(endDate: Date, count: Int) -> [DataPoint] {
var points: [DataPoint] = []
let calendar = Calendar.current
for i in 0..<count {
let date = calendar.date(
byAdding: .day,
value: -i,
to: endDate
) ?? endDate
let value = Double.random(in: 0...100)
points.append(DataPoint(date: date, value: value))
}
return points.sorted { $0.date < $1.date }
}
}
struct ScrollableChart: View {
@StateObject private var viewModel = ChartViewModel()
@State private var scrollPosition: Date
@State private var scrollDebounceTask: Task<Void, Never>?
init() {
self.scrollPosition = .now.addingTimeInterval(-4*24*3600)
}
var body: some View {
Chart(viewModel.dataPoints) { point in
BarMark(
x: .value("Time", point.date, unit: .day),
y: .value("Value", point.value)
)
}
.chartScrollableAxes(.horizontal)
.chartXVisibleDomain(length: 5 * 24 * 3600)
.chartScrollPosition(x: $scrollPosition)
.chartXScale(domain: .automatic(includesZero: false))
.frame(height: 300)
.onChange(of: scrollPosition) { oldPosition, newPosition in
scrollDebounceTask?.cancel()
scrollDebounceTask = Task {
try? await Task.sleep(for: .milliseconds(300))
if !Task.isCancelled {
checkAndLoadMoreData(currentPosition: newPosition)
}
}
}
}
private func checkAndLoadMoreData(currentPosition: Date?) {
guard let currentPosition,
let earliestDataPoint = viewModel.dataPoints.first?.date else {
return
}
let timeInterval = currentPosition.timeIntervalSince(earliestDataPoint)
if timeInterval <= 3 * 24 * 3600 {
viewModel.loadMoreData()
}
}
}
I attempted to compensate for this jump by adding:
scrollPosition = scrollPosition.addingTimeInterval(10 * 24 * 3600)
after viewModel.loadMoreData(). However, this caused the chart to jump in the opposite direction by 10 days, rather than maintaining the current position.
What's the problem with my code and how to fix it?
Running the Apple sample code “Sharing Core Data objects between iCloud users” has presented the following challenge:
After the creation of a CKRecord in a Persistent CloudKit Container private database, the owner then shares it to a participant. All works fine.
Then the Owner wants to stop sharing. That's fine too, although the CKRecord remains within the same shared zone within the owner's private database; it doesn't move back to the private database.
Then the owner wants to delete the CKRecord completely. Deletion of the record works, but evidence of the CKShare within the shared zone still remains inside the owner's private database.
It is clearly visible on the CloudKit dashboard.
Probably doesn’t take up much memory but v messy and not cool.
How to delete this CKShare completely, leaving no trace?
Any ideas would be most gratefully received!
Hi folks,
Unsure if I've implemented some sort of anti-pattern here, but any help or feedback would be great.
I've created a minimal reproducible sample below that lets you filter a list of people and mark individuals as a favourite.
When invoking the search function on a physical device running iOS 18.3.1, it crashes with Swift/ContiguousArrayBuffer.swift:675: Fatal error: Index out of range.
It runs fine on iOS 17 (physical device) and also on the various simulators I've tried (iOS 18.0, iOS 18.2, iOS 18.3.1).
If I remove the toggle binding, the crash doesn't occur (but I also can't update the toggles in the view model).
I'm expecting to be able to filter the list without a crash occurring and retain the ability to have the toggle switches update the view model.
Sample code is below. Thanks for your time 🙏!
import SwiftUI
struct Person {
let name: String
var isFavorite = false
}
@MainActor
class ViewModel: ObservableObject {
private let originalPeople: [Person] = [
.init(name: "Holly"),
.init(name: "Josh"),
.init(name: "Rhonda"),
.init(name: "Ted")
]
@Published var filteredPeople: [Person] = []
@Published var searchText: String = "" {
didSet {
if searchText.isEmpty {
filteredPeople = originalPeople
} else {
filteredPeople = originalPeople.filter { $0.name.lowercased().contains(searchText.lowercased()) }
}
}
}
init() {
self.filteredPeople = originalPeople
}
}
struct ContentView: View {
@ObservedObject var viewModel = ViewModel()
var body: some View {
NavigationStack {
List {
ForEach($viewModel.filteredPeople, id: \.name) { person in
VStack(alignment: .leading) {
Text(person.wrappedValue.name)
Toggle("Favorite", isOn: person.isFavorite)
}
}
}
.navigationTitle("Contacts")
}
.searchable(text: $viewModel.searchText)
}
}
#Preview {
ContentView()
}```
I noticed if I show a sheet from a List row, then remove the row the sheet isn't removed from the screen like it is if using VStack or LazyVStack.
I'd be interested to know the reason why the sheet isn't removed from the screen in the code below. It only occurs with List/Form. VStack/LazyVStack gives the expected result. I was wondering if it is an implementation issue, e.g. since List is backed by UICollectionView maybe the cells can't be the presenter of the sheet for some reason.
Launch on iPhone 16 Pro Simulator iOS 18.2
Tap "Show Button"
Tap "Show Sheet"
What is expected:
The sheet should disappear after 5 seconds. And I don't mean it should dismiss, I just mean removed from the screen. Similarly if the View that showed the sheet was re-added and its show @State was still true, then the sheet would be added back to the screen instantly without presentation animation.
What actually happens:
Sheet remains on screen despite the row that presented the sheet being removed.
Xcode 16.2
iOS Simulator 18.2.
struct ContentView: View {
@State var showButton = false
var body: some View {
Button("\(showButton ? "Hide" : "Show" ) Button") {
showButton = true
Task {
try? await Task.sleep(for: .seconds(5))
self.showButton = false
}
}
//LazyVStack { // does not have this problem
List {
if showButton {
SheetButton()
}
}
}
}
struct SheetButton: View {
@State var sheet = false
@State var counter = 0
var body: some View {
Text(counter, format: .number)
Button("\(sheet ? "Hide" : "Show") Sheet") {
counter += 1
sheet.toggle()
}
.sheet(isPresented: $sheet) {
Text("Wait... This should auto-hide in 5 secs. Does not with List but does with LazyVStack.")
Button("Hide") {
sheet = false
}
.presentationDetents([.fraction(0.3)])
}
// .onDisappear { sheet = false } // workaround
}
}
I can work around the problem with .onDisappear { sheet = false } but I would prefer the behaviour to be consistent across the container controls.
Just learning Swift and SwiftUI, having fun in Xcode. I have the following custom view defined, but when I try to test it, the information doesn't get updated as I expect. When I use the button defined INSIDE the custom view, the update works as expected. When I use the button defined in the Preview body, it doesn't. The "lines" variable of the custom view appears not to be updated in that case.
I know I'm missing something fundamental here about either view state binding or the preview environment, but I'm stumped. Any ideas?
import SwiftUI
struct ConsoleView: View {
var maxLines : Int = 26
private enum someIDs { case textID}
@State private var numLines : Int = 0
@State var lines = "a\nb\nc\n"
var body: some View {
VStack(alignment: .leading, spacing:0 ) {
ScrollViewReader { proxy in
ScrollView {
Button("Scroll to Bottom") {
withAnimation {
proxy.scrollTo(someIDs.textID, anchor: .bottom)
}
}
Text(lines)
.id(someIDs.textID)
.multilineTextAlignment(.leading)
.frame(maxWidth: .infinity, alignment: .bottomLeading)
.padding()
.onChange ( of: lines) {
withAnimation {
proxy.scrollTo( someIDs.textID, anchor: .bottom)
}
}
}
Button("Add more") {
writeln("More")
//writeln(response)
}
}
}
}
private func clipIfNeeded () {
if (numLines>=maxLines) {
if let i = lines.firstIndex(of: "\n") {
lines = String(lines.suffix( from: lines.index(after:i)))
}
}
}
func writeln ( _ newText : String) {
print("adding '\(newText)' to lines")
//clipIfNeeded()
write( newText )
write("\n")
numLines += 1
print(lines)
}
func write ( _ newText : String) {
lines += newText
}
}
#Preview {
VStack() {
var myConsole = ConsoleView(lines: "x\ny\nz\n")
myConsole
Button("Add stuff") {
myConsole.writeln("Stuff")
}
}
}
Hello Apple Developer Community,
I’m experiencing an issue with my iOS app, "WaterReminder," where it builds successfully in Xcode 16.2 but crashes immediately upon launch in the iPhone 16 Pro Simulator running iOS 18.3.1. The crash is accompanied by a "Thread 1: signal SIGABRT" error, and the Xcode console logs indicate a dyld error related to XCTest.framework/XCTest not being loaded. I’ve tried several troubleshooting steps, but the issue persists, and I’d appreciate any guidance or insights from the community.
Here are the details:
Environment:
Xcode Version: 16.2
Simulator: iPhone 16 Pro, iOS 18.3.1
App: WaterReminder (written in SwiftUI 6)
Build Configuration: Debug
Issue Description:
The app builds without errors, but when I run it in the iPhone 16 Pro Simulator, it shows a white screen and crashes with a SIGABRT signal. The Xcode debugger highlights the issue in the main function or app delegate, and the console logs show the following error:
dyld[7358]: Library not loaded: @rpath/XCTest.framework/XCTest
Referenced from: <549B4D71-6B6A-314B-86BE-95035926310E> /Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/WaterReminder.debug.dylib
Reason: tried: '/Users/faytek/Library/Developer/Xcode/DerivedData/WaterReminder-cahqrulxghamvyclxaozotzrbsiz/Build/Products/Debug-iphonesimulator/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/Frameworks/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/Frameworks/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/XCTest.framework/XCTest' (no such file), '/Users/faytek/Library/Developer/CoreSimulator/Devices/2A51383F-D8EA-4750-AE22-4CDE745164CE/data/Containers/Bundle/Application/56D8B44F-6613-4756-89F0-CB33991F0821/WaterReminder.app/Frameworks/XCTest.framework/XCTest' (no such file), '/Library/Developer/CoreSimulator/Volumes/iOS_22D8075/Library/Developer/CoreSimulator/Profiles/Runtimes/iOS 18.3.simruntime/Contents/Resources/RuntimeRoot/System/Library/Frameworks/XCTest.framework/XCTest' (no such file)
What I’ve Tried:
◦ Verified that FBSnapshotTestCase is correctly added to the "Embed Frameworks" build phase.
◦ Confirmed that the Framework Search Paths in build settings point to the correct location.
◦ Ensured that all required frameworks are available in the dependencies folder.
◦ Cleaned the build folder (Shift + Option + Command + K) and rebuilt the project.
◦ Checked the target configuration to ensure XCTest.framework isn’t incorrectly linked to the main app target (it’s only in test targets).
◦ Updated Xcode and the iOS Simulator to the latest versions.
◦ Reset the simulator content and settings.
Despite these steps, the app continues to crash with the same dyld error and SIGABRT signal. I suspect there might be an issue with how XCTest.framework is being referenced or loaded in the simulator, possibly related to using SwiftUI 6, but I’m unsure how to resolve it.
Could anyone provide advice on why XCTest.framework is being referenced in my main app (since it’s not intentionally linked there) or suggest additional troubleshooting steps? I’d also appreciate any known issues or workarounds specific to Xcode 16.2, iOS 18.3.1, and SwiftUI 6.
Thank you in advance for your help!
Best regards,
Faycel
I've been running into an issue using .fileImporter in SwiftUI already for a year. On iPhone simulator, Mac Catalyst and real iPad it works as expected, but when it comes to the test on a real iPhone, the picker just won't let you select files. It's not the permission issue, the sheet won't close at all and the callback isn't called. At the same time, if you use UIKits DocumentPickerViewController, everything starts working as expected, on Mac Catalyst/Simulator/iPad as well as on a real iPhone.
Steps to reproduce:
Create a new Xcode project using SwiftUI.
Paste following code:
import SwiftUI
struct ContentView: View {
@State var sShowing = false
@State var uShowing = false
@State var showAlert = false
@State var alertText = ""
var body: some View {
VStack {
VStack {
Button("Test SWIFTUI") {
sShowing = true
}
}
.fileImporter(isPresented: $sShowing, allowedContentTypes: [.item]) {result in
alertText = String(describing: result)
showAlert = true
}
VStack {
Button("Test UIKIT") {
uShowing = true
}
}
.sheet(isPresented: $uShowing) {
DocumentPicker(contentTypes: [.item]) {url in
alertText = String(describing: url)
showAlert = true
}
}
.padding(.top, 50)
}
.padding()
.alert(isPresented: $showAlert) {
Alert(title: Text("Result"), message: Text(alertText))
}
}
}
DocumentPicker.swift:
import SwiftUI
import UniformTypeIdentifiers
struct DocumentPicker: UIViewControllerRepresentable {
let contentTypes: [UTType]
let onPicked: (URL) -> Void
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
func makeUIViewController(context: Context) -> UIDocumentPickerViewController {
let documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: contentTypes, asCopy: true)
documentPicker.delegate = context.coordinator
documentPicker.modalPresentationStyle = .formSheet
return documentPicker
}
func updateUIViewController(_ uiViewController: UIDocumentPickerViewController, context: Context) {}
class Coordinator: NSObject, UIDocumentPickerDelegate {
var parent: DocumentPicker
init(_ parent: DocumentPicker) {
self.parent = parent
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
print("Success!", urls)
guard let url = urls.first else { return }
parent.onPicked(url)
}
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
print("Picker was cancelled")
}
}
}
Run the project on Mac Catalyst to confirm it working.
Try it out on a real iPhone.
For some reason, I can't attach a video, so I can only show a screenshot
In SwiftUI I want to create a list with LazyVstack and each row item in the LazyVstack is a LazyHstack of horizontally scrollable list of images with some description with line limit of 3 and width of every item is fixed to 100 but height of every item is variable as per description text content.
But in any of the rows if the first item has image description of 1 line and the remaining items in the same row has image description of 3 lines then the LazyHStack is truncating all the image descriptions in the same row to one line making all the items in that row of same height.
Why LazyHStack is not supporting items of varying height ?
Expected behaviour should be that height of every LazyHStack should automatically adjust as per item content height. But it seems SwiftUI is not supporting LazyHstack with items of varying height.
Will SwiftUI ever support this feature?
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
Hello!
How can I set appAccountToken when I'm using the new SwiftUI view SubscriptionStoreView for subscription?
Previously I was able to set it as a purchase option here https://developer.apple.com/documentation/storekit/product/purchase(options:) but I don't see purchase options with SubscriptionStoreView.
Thank you,
sendai
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)
Hello togehter,
i do have the following question.
If I have my App run in landscape mode and a sheet view get's called, will it be possible to switch automatically from landscape mode in portrait mode and fix this device orientation?
Once the sheet view get's dismissed or closed, the original view will come back and the device orientation shall switch back to landscape mode.
Thanks you so much for your help!
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
}
I want to add a tool bar (setting search )to my app just like the apple file app using pure swiftUI, is it possible, if not, can i using a UIKit to implement it.
struct MainView: View {
var body: some View {
TabView {
Tab("View 1", systemImage: "square.grid.3x2") {
View1()
}
Tab("View 2", systemImage: "square.grid.2x2") {
View2()
}
}
.tabViewStyle(.sidebarAdaptable)
}
Hi,
I found a behavioural difference in the DatePicker between WatchOS and iOS when limiting the date and time range. In the code below I'm attempting to limit the date and time range so that dates and times in past can be chosen. In iOS the DatePicker hides the dates and times that are out of range but WatchOS only the DatePicker for the date does this. The time DatePicker allows all times. The output from DatePicker is limited to the valid range, so it appears that it's the DatePicker UI that doesn't match the iOS behaviour. Does anyone know if there's a way to DatePicker that chooses the time only show valid times like iOS?
import SwiftUI
struct HistoryPeriodView: View {
@State private var selectedDate = Date()
@State private var selectedTime = Date()
var body: some View {
VStack {
// Date Picker for selecting the date (Restricts to today or earlier)
DatePicker("Select Date", selection: $selectedDate, in: ...Date.now, displayedComponents: [.date])
.labelsHidden()
// Date Picker for selecting the time (Restricts to today or earlier)
DatePicker("Select Time", selection: $selectedTime, in: ...Date.now, displayedComponents: [.hourAndMinute])
.labelsHidden()
// Display selected Date & Time
Text("\(formattedDateTime)")
.font(.footnote)
.padding()
}
}
/// Formats the selected date and time for display
private var formattedDateTime: String {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
return formatter.string(from: selectedTime)
}
}
#Preview {
HistoryPeriodView()
}