I create a toggle component based on Toggle
public struct Checkbox: View {
...
public init(...) {
...
}
public var body: some View {
return HStack(spacing: 8) {
ZStack {
Toggle("", isOn: $isPrivateOn)
...
}
...
}
}
}
how can I create a init method to support init with AppIntent like:
// Available when SwiftUI is imported with AppIntents
@available(iOS 17.0, macOS 14.0, tvOS 17.0, watchOS 10.0, *)
extension Toggle {
/// Creates a toggle performing an `AppIntent`.
///
/// - Parameters:
/// - isOn: Whether the toggle is on or off.
/// - intent: The `AppIntent` to be performed.
/// - label: A view that describes the purpose of the toggle.
public init<I>(isOn: Bool, intent: I, @ViewBuilder label: () -> Label) where I : AppIntent
}
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Posts under SwiftUI tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hello everyone, I am spending a lot of work with an application, this is based on obtaining the information from the official USCIS website, the user enters their receipt and it verifies on the USCIS website if that receipt exists, once verified it returns the information of that receipt, which I save in coredata so that the user only has to press a button to reload that information, all this is perfect, the problem is that I want the cases to be updated in the background so that the user does not have to be Entering the application, it is responsible for updating only the cases and if there was a change in your case, showing a notification to the user, I have the function of updating the cases so that when it detects a change in the database it notifies the change to the user. user, I have read the documentation but Background Task, Fetch etc. does work for me if the application is in the background that is, not closed, but when it is closed completely it does not update these cases, I have read in groups and with silent notifications to lift the application but I don't want to depend on a server, is there a method to call the function to update the cases when the application is closed (SwiftUI - Swift for iOS I am programming)
I made an extension with a UIView that takes a SwiftUI view, gets its UIView, and then adds it as a subview. But now the subview isn't receiving any touches and idk how to fix that. I've already tried point(inside:with:) but it doesn't seem to work. I've also tried forwarding the touches from touchesBegan, touchesMoved, etc., but that didn't work either.
Any help or advice would be greatly appreciated!
Extension with the UIView:
// Add view modifier to View
extension View {
func transformable() -> some View {
modifier(Transformable())
}
}
// View modifier
struct Transformable: ViewModifier {
func body(content: Content) -> some View {
TransformableUIView(content: content)
}
}
// Wrap UIView
struct TransformableUIView<V>: UIViewRepresentable where V: View {
private var content: V
init(content: V) {
self.content = content
}
func makeUIView(context: Context) -> TransformableView<V> {
TransformableView(content: content)
}
func updateUIView(_ uiView: TransformableView<V>, context: Context) {}
}
// View that handles zoom, pan, and rotate gestures
class TransformableView<V>: UIView, UIGestureRecognizerDelegate where V: View {
private var content: V
private var initialCenter: CGPoint = .zero
private var totalScale: CGFloat = 1.0
private var boundsDidSet = false
required init(content: V) {
self.content = content
super.init(frame: .zero)
self.addSubview(content.uiView)
let panGesture = UIPanGestureRecognizer(target: self, action: #selector(panPiece(_:)))
panGesture.minimumNumberOfTouches = 2
panGesture.maximumNumberOfTouches = 2
panGesture.delegate = self
self.addGestureRecognizer(panGesture)
let scaleGesture = UIPinchGestureRecognizer(target: self, action: #selector(scalePiece(_:)))
scaleGesture.delegate = self
self.addGestureRecognizer(scaleGesture)
let rotateGesture = UIRotationGestureRecognizer(target: self, action: #selector(rotatePiece(_:)))
rotateGesture.delegate = self
self.addGestureRecognizer(rotateGesture)
}
// Position content in center of view
override func layoutSubviews() {
super.layoutSubviews()
// Return if bounds are already set
if boundsDidSet {
return
}
guard let piece = self.subviews.first else { return }
piece.center = CGPoint(x: self.bounds.size.width / 2, y: self.bounds.size.height / 2)
boundsDidSet = true
}
// Function called when pan gesture is recognized
@objc private func panPiece(_ gestureRecognizer: UIPanGestureRecognizer) {
guard let piece = gestureRecognizer.view?.subviews.first else { return }
// Get the changes in the X and Y directions relative to
// the superview's coordinate space.
let translation = gestureRecognizer.translation(in: piece.superview)
if gestureRecognizer.state == .began {
// Save the view's original position.
self.initialCenter = piece.center
}
// Update the position for the .began, .changed, and .ended states
if gestureRecognizer.state != .cancelled {
// Add the X and Y translation to the view's original position.
var newCenter = CGPoint(x: initialCenter.x + translation.x, y: initialCenter.y + translation.y)
// Prevent content from leaving view
newCenter.x = clamp(value: newCenter.x, min: 0, max: self.bounds.width)
newCenter.y = clamp(value: newCenter.y, min: 0, max: self.bounds.height)
piece.center = newCenter
}
else {
// On cancellation, return the piece to its original location.
piece.center = initialCenter
}
}
// Function called when scale gesture is recognized
@objc private func scalePiece(_ gestureRecognizer : UIPinchGestureRecognizer) {
guard let piece = gestureRecognizer.view?.subviews.first else { return }
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
// Set min/max zoom
let newScale = clamp(value: totalScale * gestureRecognizer.scale, min: 0.2, max: 20) / totalScale
piece.transform = (piece.transform.scaledBy(x: newScale, y: newScale))
gestureRecognizer.scale = 1.0
totalScale *= newScale
}
}
// Function called when rotate gesture is recognized
@objc private func rotatePiece(_ gestureRecognizer : UIRotationGestureRecognizer) {
guard let piece = gestureRecognizer.view?.subviews.first else { return }
if gestureRecognizer.state == .began || gestureRecognizer.state == .changed {
piece.transform = piece.transform.rotated(by: gestureRecognizer.rotation)
gestureRecognizer.rotation = 0
}
}
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
func clamp(value: CGFloat, min: CGFloat, max: CGFloat) -> CGFloat {
if value < min {
return min
} else if value > max {
return max
} else {
return value
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Get UIView from SwiftUI View:
// Get UIView from SwiftUI View
extension View {
var uiView: UIView {
UIHostingController(rootView: self).view
}
}
ContentView:
struct ContentView: View {
var body: some View {
CanvasView()
.frame(width: 880, height: 608)
.transformable()
.background(Color.blue)
}
}
I am showing weather data in a TabView where each tab will show the forecast for that day and then an hour-by-hour Swift Charts of the temperature, chance of precipitation, and then dew point for that day. The day and a text description of that forecast correctly displays for each tab. However, the chart will only show the correct data if you perform a tap gesture on the chart.
To reproduce this issue, I do the following:
Tap on a day in the "Upcoming Week", preferably a day in the middle.
Swipe a couple days to the left or right and use the tap gesture on one of the charts.
Oddly, other data on the tab is accurate, it is really just within the SwiftChart. I did try doing a horizontal ScrollView instead but I had the same issue. I also followed the demo for SwiftCharts from WWDC.
Below is code that shows the TabView:
struct UpcomingDaysView: View {
let forecastModel:WeatherModel
@State var targetPeriod:WeatherForecastDayPeriod
var body: some View {
TabView(selection:$targetPeriod) {
ForEach(forecastModel.dailyPeriods, id: \.self) {period in
DailyViewChartDetail(forecastModel: forecastModel, periodToShow: period)
.frame(alignment: .topLeading)
.tag(period)
}
}
.containerRelativeFrame([.vertical])
.tabViewStyle(.page)
.indexViewStyle(.page(backgroundDisplayMode: .always))
.padding(EdgeInsets(top: 20, leading: 0, bottom: 0, trailing: 0))
}
}
}
And here is the DailyViewChartDetail:
struct DailyViewChartDetail: View {
var forecastModel:WeatherModel
var periodToShow:WeatherForecastDayPeriod
var body: some View {
VStack {
Text("\(DateUtility.getLongerDay(date: DateUtility.getDate(stringDate: periodToShow.dayForecast.startTime)))")
.font(.title2)
Text("\(periodToShow.dayForecast.detailedForecast)")
.font(.subheadline)
.padding(5)
HourlyViewChart(forecastModel: WeatherPeriodUtility.filterModel(forecastModel: forecastModel, targetPeriod: periodToShow))
.padding(5)
Spacer()
}
.frame(
alignment: .topLeading
)
}
}
And then some of the more relevant code in the HourlyViewChart
struct HourlyViewChart: View {
var forecastModel:WeatherModel
@State var range: (Date, Date)? = nil
@State var rawSelectedDateTemp: Date? = nil
@State var rawSelectedDatePrecipitation: Date? = nil
@State var rawSelectedDewPoint: Date? = nil
// ... more code
Below is an image that shows the issue:
I'm trying to recreate the Tag people functionality in Instagram. Where a carousel of media the user has selected is displayed to them. They can then go through and tag people to the media.
I'm trying to achieve this (but with food items instead of people) with TagView using PHAssets however the result is some funky behaviour I'm pulling my hair out trying to understand.
The items are tagging correctly but the scroll feature on the TabView works sporadically. It occasionally scrolls fine but all of a sudden won't let me scroll past one image.. (See attached video for example).
import SwiftUI
import Photos
struct TagItemView: View {
@Binding var selectedAssets: [PHAsset]
@State private var showTagSheet = false
@State private var currentAsset: PHAsset? {
didSet {
if let currentAsset = currentAsset {
assetTags = tags[currentAsset.localIdentifier] ?? []
}
}
}
@State private var tags: [String: [String]] = [:] // Dictionary to store tags for each media item
@State private var assetTags: [String] = [] // Tags for the current asset
var body: some View {
VStack {
mediaCarousel
tagsView
Spacer()
}
.background(Color.black.ignoresSafeArea())
.onAppear {
if let firstAsset = selectedAssets.first {
currentAsset = firstAsset
}
}
.onChange(of: currentAsset) { newAsset in
if let currentAsset = newAsset {
assetTags = tags[currentAsset.localIdentifier] ?? []
print("currentAsset changed: \(currentAsset.localIdentifier)")
print("assetTags: \(assetTags)")
}
}
.sheet(isPresented: $showTagSheet) {
TagSheetView(selectedAsset: $currentAsset, tags: $tags, showTagSheet: $showTagSheet, assetTags: $assetTags)
}
}
private var mediaCarousel: some View {
VStack {
TabView(selection: $currentAsset) {
ForEach(selectedAssets, id: \.self) { asset in
if asset.mediaType == .image {
TagItemImageView(asset: asset)
.tag(asset.localIdentifier)
.onAppear {
currentAsset = asset
print("Asset in view (onAppear): \(asset.localIdentifier)")
}
.onTapGesture {
currentAsset = asset
showTagSheet = true
}
} else if asset.mediaType == .video {
TagItemVideoView(asset: asset)
.tag(asset.localIdentifier)
.onAppear {
currentAsset = asset
print("Asset in view (onAppear): \(asset.localIdentifier)")
}
.onTapGesture {
currentAsset = asset
showTagSheet = true
}
}
}
}
.tabViewStyle(PageTabViewStyle(indexDisplayMode: .always))
.frame(height: UIScreen.main.bounds.height * 0.4) // Fixed height for carousel
}
}
private var tagsView: some View {
ScrollView {
if !assetTags.isEmpty {
ItemView(assetTags: assetTags, removeTag: { tag in
removeTag(tag, from: currentAsset!)
})
.transition(.opacity)
} else {
InstructionsView()
.transition(.opacity)
}
}
.background(Color.black)
.padding(.top, 8)
.padding(.horizontal, 15)
}
private func removeTag(_ tag: String, from asset: PHAsset) {
guard var assetTags = tags[asset.localIdentifier] else { return }
assetTags.removeAll { $0 == tag }
tags[asset.localIdentifier] = assetTags
if currentAsset?.localIdentifier == asset.localIdentifier {
self.assetTags = assetTags
}
}
}
Does visionOS 2 still prompt the user with a permission alert when a full immersive space is presented?
In visionOS 1, the first time an app presented an immersive space, the user was prompted with an alert to grant permission. openImmersiveSpace would return an error code if the user opted not to grant permission. In visionOS 1, it was important to handle this case correctly.
In visionOS 1, the Settings > Developer menu had an option to reset the immersive user's space permission prompting state so developers could test this interaction flow.
In visionOS 2, I no longer see the full immersive space permissions alert. I can't remember if I saw it once, the first time visionOS 2.0 beta was installed, or if I never saw it at all. The Settings > Developer menu no longer has an option to reset the permission prompting state. I can't find any way to test the interaction flow in my app to make sure that it will work correctly for users.
Does visionOS 2 no longer ask for full immersive space permission at all? I can't find this change documented anywhere.
If visionOS 2 does prompt the user for permission, is there any way to reproduce and test this interaction flow so I can make sure my app handles it correctly?
Thanks for taking the time to answer this question.
Hi!
Is there a way to increase the color contrast of the calendar version of the SwiftUI DatePicker? Even with high contrast turned on in the general IOS settings, the contrast between the "Sun", "Mon", "Tue" etc and a plain white background is only 3.86:1, which is less than the WCAG AA recommendations of 4:5:1. The contrast with the text for non-selectable dates is even lower.
I tried a couple of different options - setting tint, foregroundColor and so on, but they don't change the text color.
Thanks in advance!
Hello,
I want to write an app for following requirements:
Four views(A,B,C and D) has navigationlink as a button to move to view E.
so I wrote a navigationlink on view A as follows:
NavigationLink(destination: DestinationView(result: iOSVM.add(a: (Int(numberA) ?? 0), b: (Int(numberB) ?? 0)))) {
Text("Add?")
}
and another navigationlink on view B like this:
NavigationLink(destination: DestinationView(result:iOSVM.subtract(a:number1,b:number2))){
Text("Result?")
}
after running these codes, navigationlink on view A works properly. but another one on view B remains diabled.
help me to fix this.
thx,
c00012
This is a question regarding the specification of ObservalObject.
The following code does not cause a compilation error when the deployment target is set to iOS 16, but it does cause the following error when set to iOS 15:
class Model: ObservableObject {
let player: AVPlayer
@Published var isPlaying = false
var playerObserver: NSKeyValueObservation?
init() {
self.player = AVPlayer()
self.playerObserver = self.player.observe(\.rate, options: [.new, .old]) { player, change in
NSLog("changed rate: \(String(describing: change.newValue))")
}
}
func setup() {
let name = "sample"
let url = Bundle.main.url(forResource: name, withExtension: "m4a")!
let playerItem = AVPlayerItem(url: url)
self.player.replaceCurrentItem(with: playerItem)
}
func play() {
self.player.play()
self.isPlaying = true
}
}
The following error occurs in iOS 15:
Cannot form key path to main actor-isolated property 'rate'
Call to main actor-isolated instance method 'play()' in a synchronous nonisolated context
Additionally, if the code is modified as follows, the error does not occur even in iOS 15. Specifically, adding @MainActor to the Model resolves the issue.
@MainActor
class Model: ObservableObject {
...
}
From this behavior, I guessed that ObservableObject is implicitly a MainActor in iOS 16 and later. Is this understanding correct?
Hi!
I am working on an app that requires displaying special characters and I have currently implemented it to just use Text() in swiftUI.
Unfortunately, it can't display the full height of the text.
Attached is one example of this happening.
I have attempted to do .linespacing() but that method doesn't work. .frame also doesn't seem to make a change. Does anyone have a solution to this?
Thanks!
Hi,
I have a button view that is used in many different ways in an app that I'm working on. One of the ways it is used is in an account creation form. Since the button is in a child view, the action: { } button function isn't available in the view where the input field variables are. I could import the class with the function to the button view but I don't want to pass the input field variables into the button view. I tried binding a boolean variable to the button view and checked for it's state change in the parent view using .onChange(), but the use case for that I found was depreciated and I'm unable to revert the state of the variable in the .onChange function.
To reiterate, in a main view, I need to call a function in a given class and pass variables to it, upon a button being pressed in a child view. Any help would be greatly appreciated.
I was adding WidgetExtension target for my old project.
The widget target is running fine in iOS 17, In my case, widget need to support iOS 14 and above, so I updated my widget code to old style, To removing WidgetConfigurationIntent and AppIntentTimelineProvider.
import WidgetKit
import SwiftUI
struct Provider: TimelineProvider {
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry()
}
func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) {
completion(SimpleEntry())
}
func getTimeline(in context: Context, completion: @escaping (Timeline<SimpleEntry>) -> Void) {
completion(Timeline(entries: [SimpleEntry()], policy: .never))
}
typealias Entry = SimpleEntry
}
struct SimpleEntry: TimelineEntry {
let date: Date = Date()
}
struct NCWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
VStack {
Text("Time:")
Text(entry.date, style: .time)
}
}
}
struct NCWidget: Widget {
let kind: String = "NCWidget"
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
NCWidgetEntryView(entry: entry)
}
.configurationDisplayName("DisplayName")
.description("description")
}
}
In my case, the code was working fine in iOS 17 simulator, But if I try to run in iOS 15, it returns the below error
code-SendProcessControlEvent:toPid: encountered an error: Error Domain=com.apple.dt.deviceprocesscontrolservice Code=8 "Failed to show Widget 'com.name-pprd.NCWidgetExtension' error: Error Domain=FBSOpenApplicationServiceErrorDomain Code=5 "The request to open "com.apple.springboard" failed." UserInfo={NSLocalizedDescription=The request to open "com.apple.springboard" failed., NSLocalizedFailureReason=Unexpected error type., NSUnderlyingError=0x600003570b40 {Error Domain=BSServiceConnectionErrorDomain Code=3 "XPC error received on message reply handler" UserInfo={BSErrorCodeDescription=OperationFailed, NSLocalizedFailureReason=XPC error received on message reply handler}}, BSErrorCodeDescription=InvalidResponse}." UserInfo={NSLocalizedDescription=Failed to show Widget 'com.name-pprd.NCWidgetExtension' error: Error Domain=FBSOpenApplicationServiceErrorDomain Code=5 "The request to open "com.apple.springboard" failed." UserInfo={NSLocalizedDescription=The request to open "com.apple.springboard" failed., NSLocalizedFailureReason=Unexpected error type., NSUnderlyingError=0x600003570b40 {Error Domain=BSServiceConnectionErrorDomain Code=3 "XPC error received on message reply handler" UserInfo={BSErrorCodeDescription=OperationFailed, NSLocalizedFailureReason=XPC error received on message reply handler}}, BSErrorCodeDescription=InvalidResponse}., NSUnderlyingError=0x600003570bd0 {Error Domain=FBSOpenApplicationServiceErrorDomain Code=5 "The request to open "com.apple.springboard" failed." UserInfo={NSLocalizedDescription=The request to open "com.apple.springboard" failed., NSLocalizedFailureReason=Unexpected error type., NSUnderlyingError=0x600003570b40 {Error Domain=BSServiceConnectionErrorDomain Code=3 "XPC error received on message reply handler" UserInfo={BSErrorCodeDescription=OperationFailed, NSLocalizedFailureReason=XPC error received on message reply handler}}, BSErrorCodeDescription=InvalidResponse}}}
Domain: DTXMessage
Code: 1
User Info: {
DVTErrorCreationDateKey = "2024-07-20 17:30:58 +0000";
}
--
System Information
macOS Version 14.5 (Build 23F79)
Xcode 15.0.1 (22266) (Build 15A507)
Timestamp: 2024-07-20T23:00:58+05:30
In widget target Minimum target is 14.0
In App target Minimum target is 13.0
Hello, so I created a custom TabBar using the .overlay modifier on TabView. However, when clicking/pressing on a TextField, the keyboard causes the TabBar to be pushed up in the view. From Reddit, I found that this is caused by using the .overlay modifier.
How should I go about fixing this issue or what is the standard way of implementing custom tab bars?
Thanks in advance!
-- Kohl J
Screenshot
TabView Code
struct RootView: View {
@State var selectedTab : Tabs = .home;
var body: some View {
TabView(selection: $selectedTab) {
HomeView(selectedTab: $selectedTab)
.tag(Tabs.home)
TaskListView(selectedTab: $selectedTab)
.tag(Tabs.taskList)
CreateTaskView(selectedTab: $selectedTab)
.tag(Tabs.create)
TrophiesView(selectedTab: $selectedTab)
.tag(Tabs.trophies)
SettingsView(selectedTab: $selectedTab)
.tag(Tabs.settings)
}
.overlay(alignment: .bottom) {
TabBar(selectedTab: $selectedTab)
.padding(.horizontal)
}
}
}
Custom TabBar Code
struct TabBar: View {
@Binding var selectedTab : Tabs
var body : some View {
HStack (alignment: .center) {
Button(action: {
// switch to home view
selectedTab = Tabs.home
}, label: {
TabBarButton(buttonText: "Home", imageName: "house.fill", size: 24, isActive: selectedTab == .home, hasTopBar: true)
})
Button(action: {
// switch to task list view
selectedTab = Tabs.taskList
}, label: {
TabBarButton(buttonText: "Task List", imageName: "list.bullet.clipboard.fill", size: 24, isActive: selectedTab == .taskList, hasTopBar: true)
})
Button(action: {
// switch to create view
selectedTab = Tabs.create
}, label: {
TabBarButton(buttonText: "Create", imageName: "plus.circle.fill", size: 32, isActive: selectedTab == .create, hasTopBar: false)
})
Button(action: {
// switch to trophies view
selectedTab = Tabs.trophies
}, label: {
TabBarButton(buttonText: "Trophies", imageName: "trophy.fill", size: 24, isActive: selectedTab == .trophies, hasTopBar: true)
})
Button(action: {
// switch to settings view
selectedTab = Tabs.settings
}, label: {
TabBarButton(buttonText: "Settings", imageName: "gearshape.fill", size: 24, isActive: selectedTab == .settings, hasTopBar: true)
})
}
.frame(height: 60)
}
}
I added gesture support to my app that supports iOS 16 and 17 and have never had issues with it.
However, when I compiled my app with Xcode 16 I immediately noticed a problem with the app when I ran it in the simulator. I couldn't scroll up or down. I figured out it’s because of my gesture support.
My gesture support is pretty simple.
let myDragGesture = DragGesture()
.onChanged { gesture in
self.offset = gesture.translation
}
.onEnded { _ in
if self.offset.width > threshold {
...some logic
} else if self.offset.width < -threshold {
...some other logic
}
logitUI.debug("drag gesture width was \(self.offset.width)")
self.offset = .zero
}
If I pass nil to .gesture instead of myDragGesture then scrolling starts working again.
Here’s some example output when I’m trying to scroll down. These messages do NOT appear when I run my app on an iOS 16/17 simulator with Xcode 15.
drag gesture width was 5.333328
drag gesture width was -15.333344
drag gesture width was -3.000000
drag gesture width was -24.333328
drag gesture width was -30.666656
I opened FB14205678 about this.
I'm trying to get a countdown timer to work, and the way I currently do it in my watchOS 10 app is a complicated load of nonsense to get two Strings that look like "1w 1d" and "12:34:56", i.e. a String that shows components like year, week and day, and another String showing hours, minutes and seconds.
The new Text formats seen here https://developer.apple.com/wwdc24/10144?time=645 look useful, but I can't get them to return the values I need.
If I use this:
let dateA = Date.now
let dateB = Date.advanced(by: /* value for 8 days, 12 hours, 34 minutes and 56 seconds */)
Text(dateA, format: .offset(to: dateB, allowedFields: [.year, .week, .day], maxFieldCount: 3))
I expect to see "1 week 1 day", but it always comes back as "8 days". I guess it's giving me the most concise result, but I don't want that. I'm not sure anyone would want that.
Imagine you have an event coming up in 3 days 6 hours, do you want to see "in 78 hours" or do you want "in 3 days and 6 hours"? Why must we make the user calculate the days and hours in their head when we have the ability to give them the right information?
While I'm on this, why does the resulting String have to have "in " at the beginning? I don't want that; it's not my use case, but it's forced on me.
I've raised this a hundred times with Apple. I just want to see a String that shows the difference between two dates in a format of my choosing, i.e. "1w 1d", but they never give me what I need, so I have to write extremely complex - and fragile - code that figures this stuff out, and I still can't get that to work properly.
Why can't we just have something like:
Text(from: dateA, to: dateB, format: "%yy %ww %dd") // for "1 year 2 weeks 3 days", show parts with a value > 0
Text(from: dateA, to: dateB, format: "%0yy %0ww %0dd") // for "0 years 2 weeks 3 days", show all parts regardless of value
Text(from: dateA, to: dateB, format: "%y %w %d") // for "1y 2w 3d", show parts with a value > 0
Text(from: dateA, to: dateB, format: "%0y %0w %0d") // for "0y 2w 3d", show all parts regardless of value
Hello, community and Apple engineers. I need your help.
Our app has the following issue: NavigationStack pushes a view twice if the NavigationStack is inside TabView and NavigationStack uses a navigation path of custom Hashable elements.
Our app works with issues in Xcode 18 Beta 13 + iOS 18.0. The same issue happened on previous beta versions of Xcode 18.
The issue isn’t represented in iOS 17.x and everything worked well before iOS 18.0 beta releases.
I was able to represent the same issue in a clear project with two simple views. I will paste the code below.
Several notes:
We use a centralised routing system in our app where all possible routes for navigation path are implemented in a View extension called withAppRouter().
We have a enum RouterDestination that contains all possible routes and is resolved in withAppRouter() extension.
We use Router class that contains @Published var path: [RouterDestination] = [] and this @Published property is bound to NavigationStack. In the real app, we need to have an access to this path property for programmatic navigation purposes.
Our app uses @ObservableObject / @StateObject approach.
import SwiftUI
struct ContentView: View {
@StateObject private var router = Router()
var body: some View {
TabView {
NavigationStack(path: $router.path) {
NavigationLink(value: RouterDestination.next, label: {
Label("Next", systemImage: "plus.circle.fill")
})
.withAppRouter()
}
}
}
}
enum RouterDestination: Hashable {
case next
}
struct SecondView: View {
var body: some View {
Text("Screen 2")
}
}
class Router: ObservableObject {
@Published var path: [RouterDestination] = []
}
extension View {
func withAppRouter() -> some View {
navigationDestination(for: RouterDestination.self) { destination in
switch destination {
case .next:
return SecondView()
}
}
}
}
Below you can see the GIF with the issue:
What I tried to do:
Use iOS 17+ @Observable approach. It didn’t help.
Using @State var path: [RouterDestination] = [] directly inside View seems to help. But it is not what we want as we need this property to be @Published and located inside Router class where we can get an access to it, and use for programmatic navigation if needed.
I ask Apple engineers to help with that, please, and if it is a bug of iOS 18 beta, then please fix it in the next versions of iOS 18.0
Hello,
I'm using the Picker component to enable the user to pick a payment method but the menu items are flipped
HI,
I'm trying to deeplink from my widget to a view in my app.
I'm using the "SwiftUI app lifecycle".
This the code I'm currently using:
var body: some Scene {
WindowGroup {
RootView()
.onContinueUserActivity("NextDeparturesWidgetConfigurationIntent") { userActivity in
guard let configuration: NextDeparturesWidgetConfigurationIntent = userActivity
.widgetConfigurationIntent(),
let stationEntity = configuration.stationEntity else { return }
NotificationCenter.default.post(name: .onOpenStation, object: stationEntity.id)
}
}
}
It is working fine when the app is already running (in the background).
However when the app is "cold starting" (ie. not in memory) onContinueUserActivity is never called.
I tried adding a UIApplicationDelegateAdaptor:
func application(
_ application: UIApplication,
configurationForConnecting connectingSceneSession: UISceneSession,
options: UIScene.ConnectionOptions
) -> UISceneConfiguration {
if let userActivity = options.userActivities.first {
let configuration: NextDeparturesWidgetConfigurationIntent? = userActivity.widgetConfigurationIntent()
// casting fails
}
return UISceneConfiguration(
name: nil,
sessionRole: connectingSceneSession.role
)
}
I can see that the activity is received but it is never casted to NextDeparturesWidgetConfigurationIntent.
What am I missing ?
I have a simple SwiftUI application that sends a URLRequest as shown in the code snippet below:
import SwiftUI
@main
struct GOGODemoApp: App {
var body: some Scene {
WindowGroup {
MyView()
}
}
}
struct MyView: View {
var body: some View {
Button("Click") {
sendHTTPRequest(to: "https://www.google.com") { code, err in
print("Finished, code: \(code ?? -1), err: \(String(describing: err))")
}
}
}
}
func sendHTTPRequest(to urlString: String, completion: @escaping (Int?, Error?) -> Void) {
guard let url = URL(string: urlString) else {
completion(nil, NSError(domain: "InvalidURL", code: 0, userInfo: nil))
return
}
let task = URLSession.shared.dataTask(with: url) { _, resp, error in
if let httpResponse = resp as? HTTPURLResponse {
completion(httpResponse.statusCode, error)
} else {
completion(-1, error)
}
}
task.resume()
}
However, Xcode prints the following warning messages:
nw_connection_copy_connected_local_endpoint_block_invoke [C1] Connection has no local endpoint
nw_connection_copy_connected_local_endpoint_block_invoke [C1] Connection has no local endpoint
nw_connection_copy_connected_local_endpoint_block_invoke [C3] Connection has no local endpoint
nw_connection_copy_connected_local_endpoint_block_invoke [C3] Connection has no local endpoint
Finished, code: 200, err: nil
What does the warning 'Connection has no local endpoint' mean?
Thank you for your assistance!
For MacOS I wrote a Terminal Command Line Tool to help me do number crunching calculations. No need for UI. This works great as-is, but there are opportunities to make the work more interesting by giving it some graphical representation like a heat map of the data. To that end I want the terminal to launch a SwiftUI code to open a window given an optional command line parameter that would display this visual representation of data in a new window. It would be nice to interact with that window visualization in some ways using SwiftUI.
I originally thought it'd just be as easy as creating a SwiftUI View file and then throwing what normally appears under @main into a launch function and then calling the launch function from my main.swift file:
import SwiftUI
struct SwiftUIView: View {
var body: some View {
Text("Hello, World!")
}
}
#Preview {
SwiftUIView()
}
func LaunchSwiftUIApp()
{
//@main
struct SwiftUIApp: App {
var body: some Scene {
WindowGroup {
SwiftUIView()
}
}
}
}
Of course this doesn't work.
I've already have the command line code just spit out various png files via command line so looking to make those visualization a little more interactive or readable/organized by coding some SwiftUI stuff around those current visualizations. Anyway.
Looking around this doesn't seem to be a thing people normally do. I'm not sure how to setup the Terminal Command Line Tool code that I wrote to optionally launch into SwiftUI code.