I have updated my map code so that now I have a region that is set as a state var in my strict. My map links to this state var.
the problem is now I want to update my map based on my long and last variables that are passed to the struct is there a way to do this - going crazy trying to do this
How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here
SwiftUI
RSS for tagProvide views, controls, and layout structures for declaring your app's user interface using SwiftUI.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have an iOS 13 app that I’m hoping to release soon that is written entirely in SwiftUI. If I was starting from scratch today, I’d obviously use the new multi platform template which looks awesome.... But since I’m not starting from scratch, what are the recommendations/best practices for existing apps?
Is there a path for migrating existing apps to take advantage of the new app structure (below) when moving to iOS 14?
@main
struct HelloWorld: App {
var body: some Scene {
WindowGroup {
Text(“Hello, world!”).padding()
}
}
}
I'd like to emulate the behavior of UIViewController.isModalInPresentation in SwiftUI. In my first attempt, I defined the following view:
struct ModalView<Content: View>: UIViewControllerRepresentable {
		var content: () -> Content
		func makeUIViewController(context: Context) -> UIHostingController<Content> {
				let controller = UIHostingController(rootView: content())
				controller.isModalInPresentation = true
				return controller
		}
		func updateUIViewController(_ imagePickerController: UIHostingController<Content>, context: Context) {}
}
From my main app view, I then present the ModalView as a sheet:
struct ContentView: View {
		@State
		var presentSheet: Bool = true
		var body: some View {
				Text("Hello, world!")
						.sheet(isPresented: $presentSheet) {
								ModalView {
										Text("Sheet")
								}
						}
		}
}
But the user is still able to dismiss the ModalView by swiping down. I would expect this sheet to be non-dismissible. Is anything like this supposed to work? If not, is there some other way to prevent the dismissal of a sheet in SwiftUI?
The closest workaround I've found is to apply .highPriorityGesture(DragGesture()) to the content of the sheet, but swiping down with two fingers still works.
I have two (local) Swift packages (both with a single library product): RemoteImage, which defines setImage(from:) function on UIImageView and SatelitUI package which directly depends on the first one and defines some views. But when I'm trying to preview views from the second package I'm getting the following error:
linker command failed with exit code 1 (use -v to see invocation)
LinkDylibError: Failed to build TrailerView.swift
Linking failed: linker command failed with exit code 1 (use -v to see invocation)
ld: warning: directory not found for option '-F/Applications/Xcode-beta.app/Contents/SharedFrameworks-iphonesimulator'
Undefined symbols for architecture x86_64:
"(extension in RemoteImage):__C.UIImageView.setImage(from: Foundation.URL?) -> ()", referenced from:
(extension in SatelitUI_PreviewReplacement_TrailerView_2):SatelitUI.TrailerView.(previewupdate in _8C3731B0EF007627509BEEB93277D681)(with: SatelitUI.Trailer?) -> () in TrailerView.2.preview-thunk.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Apparently, Xcode fails to link the library from the first package because it's dynamic. Static linking works as expected.
It's a bug I believe?
On iOS 13 I used to use optional @State properties to adapt views. In my case, the presented view would either create a new object (an assignment) if the state that is passed into it is nil, or edit the assignment if an assignment was passed in. This would be done in the action block of a Button and it worked beautifully.
On iOS 14 / Xcode 12 this no longer seems to work. Given the following code which creates a new assignment and passes it into the editor view when the user taps a "New Assignment" button, the value of assignment remains nil. Is anyone else experiencing similar behaviour?
struct ContentView: View {
		@Environment(\.managedObjectContext) var context
		@State var assignmentEditorIsPresented = false
		@State var assignment: Assignment? = nil
		var Body: some View {
				[...]
				Button("New Assignment", action: {
						self.assignment = Assignment(context: context)
						self.assignmentEditorIsPresented = true
				})
				.sheet(isPresented: assignmentEditorIsPresented) {
						[...]
				}
		}
}
What's even weirder is that I tried adding a random piece of state, an Int, to this view and modifying it right before the assignment state (between lines 9 and 10) and it didn't change either.
Hello, My Custom fonts are not showing in SwiftUI. I am all up to date on all of my software and I have added my TTF's to a fonts folder in my collection. I also added the "Fonts provided by application" array type to my info.plist and the fonts as elements. Here is my code. I have no idea what I'm doing wrong. Is there a bug in the latest version of Swiftui?
Text("Hello World")
			.font(.custom("VervelleScript-lgxR0", size: 36))
Hi,
I have added widgets to my iOS app and I would like to make this feature only accessible to "pro" users that have made a non-consumable in-app purchase.
Currently, I am doing the following: I store an "isUnlocked" property in the Keychain after the purchase is made
I read data to be displayed in the widget and here I also query the Keychain and store whether the widget is unlocked
I have no refresh policy, but only change the widget data on a significant time change
a different view is displayed when the app is locked
Some dummy code snippets:
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> Void) {
		let entry = readContents()
		let timeline = Timeline(entries: [entry], policy: .never)
		completion(timeline)
}
struct WidgetEntryView: View {
		let entry: Provider.Entry
@Environment(\.widgetFamily) var family
@ViewBuilder
var body: some View {
switch family {
case .systemSmall:
if !entry.isUnlocked {
LockedWidgetView()
} else if let event = entry.event {
SmallWidgetEventView(event: event)
} else {
NoDataWidgetView()
}
...
func applicationSignificantTimeChange(_ application: UIApplication) {
		if #available(iOS 14.0, *) {
				WidgetCenter.shared.reloadAllTimelines()
		}
...
However, 2 unexpected things happen: the view is refreshed intraday (not only at midnight i.e. at significant time change)
sometimes the LockedWidgetView is displayed.
Especially the latter is problematic, because it gives false information to a user that has already made the in-app purchase.
How can I achieve my goal of only displaying info when the user has made the in-app purchase?
Thanks in advance.
P.S. Although it would not have my preference, I would also find it acceptable if the widget is only shown as option to add once the purchase is made. In other words, I was considering changing the Widget itself:
struct MyWidget: Widget {
private var supportedFamilies: [WidgetFamily] = isUnlocked() ? [.systemSmall, .systemMedium] : []
but I believe I cannot re-initialise the widget from the app when the user makes the in-app purchase, because the only refresh option that I have is
WidgetCenter.shared.reloadAllTimelines()
Introduction
I created a simple app to test enabling Sign In with Google using Observable Objects in a SwiftUI Application. However, the app only functions properly (displaying the signed in user's name and email) with a UIKit App Delegate Life Cycle. The code of the App file for the SwiftUI life cycle and that of the app delegate and scene delegate files of the UIKit App Delegate life cycle should function identical; however, they do not.
Project Code
SwiftUI Lift Cycle
AppDelegate
import UIKit
import SwiftUI
import GoogleSignIn
class AppDelegate: NSObject, UIApplicationDelegate {
/* GoogleDelegate() is the observable object */
let googleDelegate = GoogleDelegate()
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
GIDSignIn.sharedInstance()?.clientID = "CLIENT_ID"
GIDSignIn.sharedInstance()?.delegate = googleDelegate
return true
}
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
return GIDSignIn.sharedInstance().handle(url)
}
}
App
@main
struct WidgiTubeApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var window: UIWindow? {
guard let scene = UIApplication.shared.connectedScenes.first,
let windowSceneDelegate = scene.delegate as? UIWindowSceneDelegate,
let window = windowSceneDelegate.window else {
return nil
}
return window
}
@Environment(\.scenePhase) private var scenePhase
let googleDelegate = (UIApplication.shared.delegate as! AppDelegate).googleDelegate
var body: some Scene {
WindowGroup {
GoogleSignInView()
.environmentObject(googleDelegate)
}.onChange(of: scenePhase) { (phase) in
switch phase {
case .active:
GIDSignIn.sharedInstance().presentingViewController = window?.rootViewController
window?.makeKeyAndVisible()
case .inactive:
case .background:
default:
}
}
}
}
Using the SwiftUI Life Cycle the User Is signed in; however, the information does not update in the SwiftUI view. (The view is identical between the SwiftUI Life Cycle and UIKit Application Delegate Life Cycle.)
UIKit Application Delegate Life Cycle
App Delegate
DidFinishLaunchingWithOptions
GIDSignIn.sharedInstance().clientID = "CLIENT_ID"
GIDSignIn.sharedInstance().delegate = googleDelegate
return true
OpenURL
return GIDSignIn.sharedInstance().handle(url)
Scene Delegate
SceneWillConnectTo
let googleDelegate = (UIApplication.shared.delegate as! AppDelegate).googleDelegate
let contentView = ContentView().environmentObject(googleDelegate)
if let windowScene = scene as? UIWindowScene {
let window = UIWindow(windowScene: windowScene)
window.rootViewController = UIHostingController(rootView: contentView)
GIDSignIn.sharedInstance()?.presentingViewController = window.rootViewController
self.window = window
window.makeKeyAndVisible()
}
Conclusion
Due to this, I have identified that there must be some issue that occurs when adapting the UIKit App Delegate code to the SwiftUI App Code. However, I cannot identify what the issue between the two life cycles is. It is my understanding that anything possible with the UIKit Delegate life cycle should theoretically be possible with SwiftUI. In the mean time, of course, there is no issue continuing with the UIKit Delegate; however, I was hoping to create a SwiftUI app. If anyone could help me identify where the issue lays between these two different life cycles, I would greatly appreciate it. Thanks!
Hello.
I have successfully created a scrollview with several buttons that stack on top of one another. But the View won't scroll. What am i doing wrong here?
scrollView = UIScrollView.init(frame: CGRect.zero)
				scrollView.translatesAutoresizingMaskIntoConstraints = false
				
				
				self.view.addSubview(scrollView)
				var leadingAnchor = self.scrollView!.topAnchor
				for i in 0..<20{
						let t_button = UIButton.init(frame: CGRect.zero)
						t_button.translatesAutoresizingMaskIntoConstraints = false
						t_button.backgroundColor = UIColor.blue
						scrollView.addSubview(t_button)
						NSLayoutConstraint.activate([
								t_button.topAnchor.constraint(equalTo: leadingAnchor, constant:5.0),
								t_button.centerXAnchor.constraint(equalTo: scrollView.centerXAnchor),
								t_button.heightAnchor.constraint(equalToConstant: 50.0),
								t_button.widthAnchor.constraint(equalToConstant: 75.0)
						])
						
						leadingAnchor = t_button.bottomAnchor
						
						t_button.setTitle("Button \(i)", for: .normal)
						t_button.addTarget(self, action: #selector(scrollViewButtonAction(_:)), for: .touchUpInside)
						
				}
				
				NSLayoutConstraint.activate([
						scrollView.topAnchor.constraint(equalTo: self.titleHeader.bottomAnchor, constant: 10.0),
						scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor),
						scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor),
						scrollView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor),
				])
I've been using the new template for a document-based SwiftUI app. While you get a lot of file-management "for free" in the new template, as it stands in the iOS version users have to back out of the file to the file browser to change the filename. I want to create an opportunity for the user to rename the file while it is open.
Here's a sample project focused on the issue: https://github.com/stevepvc/DocumentRenamer
In the code, I've added to the template code a simple UI with a textfield for the user to enter a new name. When the user hits the "rename" button, the app checks to see if the URL with that name component is available, appending a suffix if necessary to create a target url.
func getTargetURL() -> URL {
		let baseURL	=	self.fileurl.deletingLastPathComponent()
		print("filename: \(self.filename)")
		print("fileURL: \(self.fileurl)")
		print("BaseURL: \(baseURL)")
		var target = URL(fileURLWithPath: baseURL.path + "/\(filename).exampletext")
		var nameSuffix = 1
		
		while (target as NSURL).checkPromisedItemIsReachableAndReturnError(nil) {
				
				target = URL(fileURLWithPath: baseURL.path + "/\(filename)-\(nameSuffix).sermon")
				print("Checking: \(target)")
				nameSuffix += 1
	 }
		print("Available Target: \(target)")
		return target
}
It then attempts to rename the file, and this is when I am stuck. I have tried several methods, most recently the following:
func changeFilename(){
		let target	= getTargetURL()
		var rv = URLResourceValues()
		let newFileName = target.deletingPathExtension().lastPathComponent
		rv.name = newFileName
		do {
				if fileurl.startAccessingSecurityScopedResource(){
						try fileurl.setResourceValues(rv)
						fileurl.stopAccessingSecurityScopedResource()
				}
		} catch {
				print("Error:\(error)")
		}
}
But I keep getting the following error whenever I run the app on a device:
Domain=NSCocoaErrorDomain Code=513 "You don’t have permission to save the file “Untitled” in the folder “DocumentRenamer”."
I have also tried this without the startAccessingSecurityScopedResource() check, and alternatively have tried creating a helper class as follows:
class FileMover: NSObject {
func moveFile(originalURL: URL, updatedURL:URL) -> Bool {
		let coordinator = NSFileCoordinator(filePresenter: nil)
		var writingError: NSError? = nil
		var success : Bool = true
		print("moving file")
		coordinator.coordinate(writingItemAt: originalURL, options: NSFileCoordinator.WritingOptions.forMoving, error: &writingError, byAccessor: { (coordinatedURL) in
				do {
						try FileManager.default.moveItem(at: coordinatedURL, to: updatedURL)
						success = true
						print("file moved")
						
				} catch {
						print(error)
						success = false
				}
		})
return success
		
}
}
But using this method locks up the app entirely.
What is the correct method for renaming a file in the app's container, particularly using the new Swiftui Document based template?
I have a List in a sidebar style which contains a LazyVGrid and a Section with a simple list contents. Every thing works well except when content increases and layout changes (from two columns to one column) for the LazyVGrid with editMode changing to .active ... LazyVGrid does not expand/resize when the content increases (the increased content gets clipped)...but does when user expands/folds on the section below :(. However LazyVGrid resizes to show the entire content when the content shrinks with editMode reverting to .inactive
Note: If I replace the List with a ScrollView...lazyVGrid resizes perfectly when content increases in editMode = .active....but then I would lose all the Sidebar and List characteristics for the Section below :(
Also, looks like .onMove is not supported in LazyVGrids
Any pointers to solve the LazyVGrid (embedded in a List) not resizing or expanding when content increases ... will be deeply appreciated.
var body: some View {
List {
LazyVGrid(columns: editMode?.wrappedValue == .active ? singleColumn : twoColumns, alignment: .leading, spacing: 10) {
ForEach(editMode?.wrappedValue == .active ? allDashItems : selectedDashItems) { dashitem in
DashItemCell(dashitem)
}
.onMove(perform: moveDashItem)
.environment(\.editMode, editMode)
}
Section(header: Text("Bottom Section")) {
ForEach (sectionList)	{ item in
ListItemCell(item)
}
.onDelete(perform: deleteFolder)
.onMove(perform: moveFolder)
}
}
.listStyle(SidebarListStyle())
}
I am developing an app in swiftUI using Xcode 12.3, deployment target iOS 14.0. The launch screen is setup through info.plist by specifying 'background color' and 'image name'. The file used in 'image name' is from Assets catalog. (PNG format, size300 x 300 and corresponding @2x and @3x resolutions) What I have observed, when the app is installed for the first time the launch image is centered and have original resolutions but all subsequent launches show launch images stretched to cover full screen. Any ideas why this is happening and how to have more consistent behavior either way?
I have tried 'respect safe area' option but it does not make a difference.
Thank you.
In a SwiftUI lab, I was asking about setting the focus state down a view hierarchy. The answer I got was to pass the focus state down the views as a binding. Conceptually, that made sense, so I moved on to other questions. But now that I am trying to implement it, I am having problems.
In the parent view, I have something like this:
@FocusState private var focusElement: UUID?
Then I am setting a property like this in the child view:
@Binding var focusedId: UUID?
When I try to create the detail view, I'm trying this:
DetailView(focusedId: $focusElement)
But this doesn't work. The error I get is:
Cannot convert value of type 'FocusState<UUID?>.Binding' to expected argument type 'Binding<UUID?>'
What is the right way to pass down the focus state to a child view so that it can update back up to the parent view?
I am trying to update from one child view, and have a TextField in a sibling view get focus.
I have been playing around with the new AsyncImage Api in SwiftUI
I am using the initialiser that passes in a closure with the AsyncImagePhase, to view why an image may not load, when I looked at the error that is passed in if the phase is failure, the localised description of the error is "Cancelled" but this is happening before the view is being displayed.
I am loading these images in a list, I imagine I am probably doing something which is causing the system to decide to cancel the loading, but I cannot see what.
Are there any tips to investigate this further?
A simple button in SwiftUI does not have an accurate tap area. It's supposed to react to the tap gesture only when the user is tapping inside the bounds. But it's not.
iOS 14.5
Xcode 12.5.1 (12E507)
I'm trying to understand a design pattern for accessing the isolated state held in an actor type from within a SwiftUI view.
Take this naive code:
actor Model: ObservableObject {
@Published var num: Int = 0
func updateNumber(_ newNum: Int) {
self.num = newNum
}
}
struct ContentView: View {
@StateObject var model = Model()
var body: some View {
Text("\(model.num)") // <-- Compiler error: Actor-isolated property 'num' can not be referenced from the main actor
Button("Update number") {
Task.detached() {
await model.updateNumber(1)
}
}
}
}
Understandably I get the compiler error Actor-isolated property 'num' can not be referenced from the main actor when I try and access the isolated value. Yet I can't understand how to display this data in a view. I wonder if I need a ViewModel that observes the actor, and updates itself on the main thread, but get compile time error Actor-isolated property '$num' can not be referenced from a non-isolated context.
class ViewModel: ObservableObject {
let model: Model
@Published var num: Int
let cancellable: AnyCancellable
init() {
let model = Model()
self.model = model
self.num = 0
self.cancellable = model.$num // <-- compile time error `Actor-isolated property '$num' can not be referenced from a non-isolated context`
.receive(on: DispatchQueue.main)
.sink { self.num = $0 }
}
}
Secondly, imagine if this code did compile, then I would get another error when clicking the button that the interface is not being updated on the main thread...again I'm not sure how to effect this from within the actor?
Hello
I want to be able to save Date in @AppStorage, and it works however I was wondering what was the difference between these two extensions, which one is better and why?
extension Date: RawRepresentable {
static var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .long
return formatter
}()
public var rawValue: String {
Date.dateFormatter.string(from: self)
}
public init?(rawValue: String) {
self = Date.dateFormatter.date(from: rawValue) ?? Date()
}
}
and
extension Date: RawRepresentable {
private static let formatter = ISO8601DateFormatter()
public var rawValue: String {
Date.formatter.string(from: self)
}
public init?(rawValue: String) {
self = Date.formatter.date(from: rawValue) ?? Date()
}
}
Thank You!
This question was originally posted to StackOverflow, but I found it more suitable to be placed here.
Was working on migrating one of my app from AppDelegate lifecycle to SwiftUI lifecycle according to this question.
After following all the steps, The simulator simply shows a blank screen (the app does not launch at all):
There is no log in the console. However, if the app is removed from the simulator (or device) and reinstalled, it will launch the new SwiftUI lifecycle correctly. So there seems to be some problem with scene caching that causes iOS to be confused after the migration.
Am I missing something during the migration?
Use Case
If you have a ContentView that displays a pausable view based on a
@State private var presentSheet = false
property that is also used to present a
.sheet(isPresented: $presentSheet)
if:
the property is sent to the PausableView(isPaused: presentSheet) as a normal property, the body of the ContentView and the body of the sheet is being redrawn when the sheet is dismissed
the property is sent to the PausableView(isPaused: $presentSheet) as a @Binding, the body of the ContentView and the body of the sheet is NOT redrawn when the sheet is dismissed
Is this normal behavior?
The ContentView body makes sense to change, but is the sheet's body also supposed to be redrawn when the sheet is not presenting anymore after dismiss?
Sample Project
A sample project created in Xcode 13 is available here: https://github.com/clns/SwiftUI-sheet-redraw-on-dismiss. I noticed the same behavior on iOS 14 and iOS 15.
There are also 2 animated gifs showing the 2 different behaviors in the GitHub project.
The relevant code is in ContentView.swift:
import SwiftUI
struct DismissingView: View {
@Binding var isPresented: Bool
var body: some View {
if #available(iOS 15.0, *) {
print(Self._printChanges())
} else {
print("DismissingView: body draw")
}
return VStack {
Button("Dismiss") { isPresented.toggle() }
Text("Dismissing Sheet").padding()
}.background(Color.white)
}
}
struct PausableView: View {
var isPaused: Bool
// @Binding var isPaused: Bool
private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
@State private var counter = 0
var body: some View {
Text("Elapsed seconds: \(counter)")
.onReceive(timer) { _ in
counter += isPaused ? 0 : 1
}
}
}
struct ContentView: View {
@State private var presentSheet = false
var body: some View {
if #available(iOS 15.0, *) {
print(Self._printChanges())
} else {
print("ContentView: body draw")
}
return VStack{
Button("Show Sheet") { presentSheet.toggle() }
Text("The ContentView's body along with the .sheet() is being redrawn immediately after dismiss, if the @State property `presentSheet` is used anywhere else in the view - e.g. passed to `PausableView(isPaused:presentSheet)`.\n\nBut if the property is passed as a @Binding to `PausableView(isPaused:$presentSheet)`, the ContentView's body is not redrawn.").padding()
PausableView(isPaused: presentSheet)
// PausableView(isPaused: $presentSheet)
}
.sheet(isPresented: $presentSheet) {
DismissingView(isPresented: $presentSheet)
.background(BackgroundClearView()) // to see what's happening under the sheet
}
}
}
The Build for Previews builds all my targets including the test targets. Is there a way to configure the relevant targets? I do not see an option in the schema editor, and disabling Find Implicit Dependencies has no effect either.