I've found that AsyncImages tend to take up a lot of space in the tmp folder with a bunch of CFNetworkDownload files. Is there a simple way to clear the tmp file on load in Swift (using SwiftUI)?
import SwiftUI
struct MyView: View {
var body: some View {
TabView {
// Content
}
.onAppear {
// Clear tmp folder
}
}
}
Related
I'm trying to made an WatchOS extension with the new type .accessoryInlineBut I don"t understand why I cannot have more than one stack in the main horizontal stack.
See the invisible stack in the following commented code and in the WatchOS simulator
struct WidgetInlineView : View {
var entry: BurnoutTimelineEntry
var body: some View {
HStack(spacing: 5) {
HStack {
Image("widgetWork")
Text(entry.exchange.todayWork.durationString)
}
HStack {
Image("widgetPause")
Text(entry.exchange.todayPause.durationString)
}
}
}
}
struct WidgetInline: Widget {
var body: some WidgetConfiguration {
StaticConfiguration(kind: "MyKind", provider: BurnoutTimelineProvider()) { entry in
WidgetInlineView(entry: entry)
}
.configurationDisplayName("My Widget")
.description("This is an example widget.")
.supportedFamilies([.accessoryInline])
}
}
struct WidgetInline_Previews: PreviewProvider {
static var previews: some View {
WidgetInlineView(entry: BurnoutTimelineEntry(date: Date()))
.previewContext(WidgetPreviewContext(family: .accessoryInline))
}
}
The inline widgets only display the first text item and the first image. Everything else is ignored and they ignore any styling, too. And to top it off, it's very picky about the image size (I have not found the exact limits yet): if your image is too large it won't get rendered, even if you marked it as resizable.
I come to the same conclusion as answered by #DarkDust
Regarding text, my work around is to use text concatenation. something like this...
Text("Hello") + Text("\(name) ") + Text(Image(systemName: "exclamationmark.circle.fill"))
How can I prevent a view within a Sheet from inheriting components from its parents?
I believed a Sheet would create a whole new view hierarchy, but apparently it does not completely. As seen in the Gif below, the ListView inherits the Form when it is attached to the Button inside the Form. When placing it outside the form, the List behaves as expected. Is there a way to prevent this from happening? As you can see, the list with its sections becomes pretty useless when inheriting the Form. This almost seems like a bug to me.
Tested in an empty project using Xcode Version 12.5 (12E262) and iOS 14.5
import SwiftUI
struct ContentView: View {
#State var isSheetPresented: Bool = false
var body: some View {
NavigationView {
Form {
NavigationLink ("Link", destination: ListView())
Button("Sheet") {
isSheetPresented = true
}
.sheet(isPresented: $isSheetPresented, content: {
NavigationView {
ListView()
}
})
}
}
}
}
struct ListView: View {
var body: some View {
List {
Button("1") { }
Button("2") { }
Button("3") { }
Section(header: Text("one")) {
Button("4") { }
}
}
.navigationBarTitle("List")
}
}
Use DefaultListStyle()
ListView().listStyle(DefaultListStyle())
I'm struggling to replace the root view in a pure SwiftUI app. There is no SceneDelegate or AppDelegate. The entry point of the app was originally as follows.
import SwiftUI
#main
struct SampleApp: App {
var body: some Scene {
WindowGroup {
MainTabView()
}
}
}
I haven't been able to find any resources that don't leverage the old "delegates". The best I could come up with was to bind to an observable object, but for some reason it's not working.
import SwiftUI
#main
struct SampleApp: App {
let myController = MyController.shared
var body: some Scene {
WindowGroup {
if myController.isUserFullscreen {
FullScreenView()
} else {
MainTabView()
}
}
}
}
In order for your code to update, SwiftUI has to know to look for changes. Most commonly, this is done with an #ObservableObject or #StateObject. Right now, you just have a regular property called myController -- SwiftUI won't know to respond to changes.
You didn't give any information about what MyController is, but I can make some assumptions and turn it into an ObservedObject:
class MyController : ObservableObject {
static let shared = MyController()
#Published var isUserFullscreen = false
}
Then, in your view, you can redefine your property as:
#ObservedObject var myController = MyController.shared
Then, your view should know to respond to changes on the #Published property of the #ObservableObject.
Here's some more reading on #ObservableObject : https://www.hackingwithswift.com/quick-start/swiftui/observable-objects-environment-objects-and-published
I just started using CoreData with SwiftUI.
After following this series of tutorial.
And I am facing a situation where I cannot save data as I expect. Here is the relevant code:
struct MyView: View {
......
#Environment(\.managedObjectContext) var managedObjectContext
func setData() {
print(#function)
.....
let myData = SomeEntity(context: self.managedObjectContext)
myData.name = "myName"
myData......
do {
try self.managedObjectContext.save()
} catch let error {
// Handle the Core Data error.
print("Can't save as expected!!!!")
print("Error : \(error)")
}
}
.....
var body: some View {
........
}
}
When this code executes I get this error:
Can't save as expected!!!!
Error : nilError
Can somebody tell me what I need to check?
I am all the more puzzled, that I have another part in my app (apparently similar), in a view one level above, where the saving is perfectly working.
In case this may be useful, the view is presented with code like this:
}).sheet(isPresented: $showingFlag) {
MyView(.....)
}
In the presenting view, data saving is working.
Sheets and alerts, etc are modal views. Modal views are normal views, but they are not part of the interface's view hierarchy and are presented on top of the rest of the views on the screen. This means they do not have automatic access to the same #Environment variables that were injected into the interface's view hierarchy (usually in the SceneDelegate or the newer SwiftUI App life-cycle).
To access that same managedObjectContext variable inside the modal View you can pass it along using standard dependency injection.
}).sheet(isPresented: $showingFlag) {
MyView(context: managedObjectContext)
}
struct MyView: View {
......
var context: NSManagedObectContext!
func setData() {
print(#function)
I need to open a view called PackageDetails.
There are two cases in which this view could be opened.
1. If you tap a specific Package from a list of packages.
I have an array of all the packages. So I'm passing the specific struct from this list and I'm opening this package view.PackageDetail(package: package). I already have all the data I need so I do not need to make an extra call to Firestore to fetch this document.
2. Package view can be opened by a link from some other view in this app.
In this case I do not have all the details of this specific Package but I have just a reference to the Firestore document. I am using this reference to make a query as soon as this view appears and get the details about this Package PackageDetail(package: packageReference)
The ways I'm doing this is by declaring Package as an Optional #State var package: PackageModel? and onAppear I'm checking if the Package is null or not.
.onAppear {
if let package = self.package {
// package data exists
} else {
// fetch it from firestore
}
}
The question is: Am I doing this right? Is this the best approach?
The Package is not view state, so #State, by design does not fit here. Instead it is preferable to use view model pattern, so the approach (scratchy) might be like below:
class PackageViewModel: ObservableObject {
#Published var packageReference: URL?
#Published var package: PackageModel?
init(package: PackageModel? = nil, reference: URL? = nil) {
self.package = package
self.packageReference = reference
}
private func loadPackage() {
// do load here from 'self.packageReference' and in callback assign package created from result
DispatchQueue.main.async {
self.package = package
}
}
}
struct PackageView: View {
#ObservedObject var vm: PackageViewModel
var body: some View {
VStack {
// some main part here
if vm.package != nil {
PackageDetail(package: self.vm.package)
}
}
.onAppear {
if self.vm.package == nil {
self.vm.loadPackage()
}
}
}
}