So I have a perplexing situation. I'm loading multiple SwiftUI AsyncImages according to spec (see code below). For some reason, my 1MB app has over 400+ MBs of documents & data. When I view the app's container, I can see that it is caused by a massive number of the images as .tmp files in the "tmp" folder all starting with the name "CFNetworkDownload". It seems that every time an image is loaded, it's stored in here, but does not delete. This makes the app get bigger every time it's opened. What can I do about this issue? Thanks so much! (P.S. I've tried to condense my code down as much as possible for readability, but there's a few files included because I'm not sure where the problem lies.)
Main app Swift file:
@main
struct MyApp: App {
let monitor = NWPathMonitor()
@State private var isConnected = true
var body: some Scene {
monitor.pathUpdateHandler = { path in
if path.status == .satisfied {
if !isConnected {
isConnected.toggle()
}
}
else {
if isConnected {
isConnected.toggle()
}
}
}
let queue = DispatchQueue(label: "Monitor")
monitor.start(queue: queue)
return WindowGroup {
isConnected ? AnyView(ContentView()) : AnyView(ContentViewFailed())
}
}
}
The ContentView that's loaded inside the above WindowGroup:
struct ContentView: View {
var body: some View {
TabView {
HomeView()
.tabItem {
Image(systemName: "house.fill")
Text("Home")
}
. . .
}
}
}
And finally, the HomeView where the images are being loaded:
struct HomeView: View {
var body: some View {
let urlString = "https://www.example.com/Home.json"
if let url = URL(string: urlString) {
if let data = try? Data(contentsOf: url) {
do {
items = try JSONDecoder().decode([Item].self, from: data)
}
catch {
print(error)
}
}
}
return NavigationView {
List {
ScrollView {
VStack(alignment: .leading) {
ZStack {
VStack(alignment: .leading) {
Spacer()
HStack {
AsyncImage(url: URL(string: "https://www.example.com/images/example.png")) { image in
image
.resizable()
.aspectRatio(contentMode: .fill)
.shadow(color: Color(red: 0, green: 0, blue: 0, opacity: 0.25), radius: 1)
} placeholder: {
ProgressView()
.progressViewStyle(.circular)
}
.frame(width: 202, height: 100)
}
. . .
}
}
}
}
}
}
}
}
I really appreciate your time. Not sure if this could just be a bug with AsyncImage itself.
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.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Created
Hi,
I have an existing AppKit-based Mac app that I have been working on for a few years. For a new feature, I wanted to have the app opened by a different app, so I setup the URL scheme under CFBundleURLTypes in my Info.plist, and adopted this delegate callback:
- (void)application: (NSApplication *)application openURLs:(nonnull NSArray<NSURL *> *)urls
Now when I invoke the URL from the 2nd app, it opens my app correctly, BUT this delegate method isn't called. What's interesting is that if I make a totally new app with a URL scheme and adopt this delegate method, it gets called without a problem!
SO what about my original project could be responsible for this 'opensURLs' method to not be called? I've been searching for a solution for a couple of days without any luck. The macOS app's target has a Deployment Target of 10.15 and I'm running this on macOS12.0 with Xcode 13.
I'm using UIDocumentPickerViewController to import document to my app from OneDrive and I want to show the OneDrive folder every time I use UIDocumentPickerViewController instead of the last folder I opened. Is it possible? Can I use pickerController.directoryURL ? And how to get folder URL of OneDrive?
class ViewController: UIViewController, DocumentDelegate {
var picker: DocumentPicker?
override func viewDidLoad() {
super.viewDidLoad()
picker = DocumentPicker(presentationController: self, delegate: self)
}
@IBAction func create_picker(_ sender: Any) {
picker?.presentDocumentPicker()
}
func didPickImage(image: UIImage?) {}
}
protocol DocumentDelegate: AnyObject {
func didPickImage(image: UIImage?)
}
class DocumentPicker: NSObject {
private var pickerController: UIDocumentPickerViewController?
private weak var presentationController: UIViewController?
private weak var delegate: DocumentDelegate?
init(presentationController: UIViewController,
delegate: DocumentDelegate) {
super.init()
self.presentationController = presentationController
self.delegate = delegate
}
func presentDocumentPicker() {
pickerController = UIDocumentPickerViewController(forOpeningContentTypes: [.image])
if let pickerController = pickerController {
pickerController.delegate = self
pickerController.allowsMultipleSelection = false
presentationController?.present(pickerController, animated: true)
}
}
}
extension DocumentPicker: UIDocumentPickerDelegate {
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
guard let url = urls.first else { return }
print(url)
}
}
I'm working on an app targeting iOS 15+ using SwiftUI.
The app has several Views that load data from an API in their onAppear() method. While the loading operation is in progress, these views show a loading overlay via .fullScreenCover().
While most of the time this works as expected, I've discovered that if the API operation completes before the overlay's .onAppear() has fired, the overlay gets stuck on screen, i.e. does not dismiss. This bug occurs both in the simulator and on device.
This is a simplified version of my implementation:
struct MyDataView: View {
@EnvironmentObject var store:Store
var Content: some View {
// ...
}
@ViewBuilder
var body: some View {
let showLoadingOverlay = Binding(
get: {
store.state.loading
},
set: { _ in }
)
Content
.onAppear {
store.dispatch(LoadData)
}
.fullScreenCover(isPresented: showLoadingOverlay) {
LoadingOverlay()
}
}
}
Log messages tell me that my store is updating correctly, i.e. the booleans all operate as expected. Adding log output to the binding's getter always prints the correct value. Adding a breakpoint to the binding's getter makes the problem disappear.
I've found that the chronology of events that lead to this bug is:
MyDataView.onAppear()
LoadData
Binding: true
Overlay starts animating in
LoadData finishes
Binding: false
Overlay fires it's onAppear
I.e. whenever loading finishes before the fullScreenCover's onAppear is fired, the overlay get's stuck on screen. As long as loading takes at least as long as it takes the overlay to appear, the bug does not occur.
It appears to be a race condition between the .fullScreenCover appearing and the binding changing to false.
I've found that the bug can be avoided if loading is triggered in the overlay's .onAppear(). However, I would like to avoid this workaround because the overlay is not supposed to carry out data loading tasks.
I noticing that Monterey defaults to the NSWindowToolbarStyleAutomatic / NSWindowToolbarStyleUnified toolbar style, which suppresses the "use Small Size" menu item and customization checkbox.
So I've set the window to use NSWindowToolbarStyleExpanded. However, the toolbar will no longer change to a smaller icon size, as it did in MacOS 10.14, 10.15, and 11.0.
I've tried to set the toolbar item sizing to "Automatic" for all of our toolbar icons, but that results in bad positioning in both Regular and Small Size mode -- the height is way too big.
The native size of the icon .png files are 128 x 128. What's odd is that if I resize the window with the toolbar to be wider, the NSToolbarItems in the overflow area will be displayed in the toolbar are 128 x 128, where the rest of the toolbar icons get displayed as a 32 x 32 icon.
The only way to get it to layout remotely correct is to make the NSToolbarItem to have an explicit minimum size of 24 x 24 and maximum size of 32 x 32. And that USED to allow "small size", but on Monterey, it no longer does.
Anyone had any success with small size icons on Monterey?
Hey,
I know you can write @AppStorage("username") var username: String = "Anonymous" to access a Value, stored In the User Defaults, and you can also overwrite him by changing the value of username.
I was wondering if there is any workaround to use @AppStorage with Arrays.
Because I don't find anything, but I have a lot of situations where I would use it.
Thanks!
Max
Don’t over-engineering! No suggested architecture for SwiftUI, just MVC without the C.
On SwiftUI you get extra (or wrong) work and complexity for no benefits. Don’t fight the system.
When i have TextField inside ScrollView and tap on it the keyboard is shown as expected. But it seems that the TextField is moved up just enough to show the input area but i want to be moved enough so that is visible in its whole. Otherwise it looks cropped. I couldn't find a way to change this behaviour.
struct ContentView: View {
@State var text:String = ""
var body: some View {
ScrollView {
VStack(spacing: 10) {
ForEach(1...12, id: \.self) {
Text("\($0)…")
.frame(height:50)
}
TextField("Label..", text: self.$text)
.padding(10)
.background(.white)
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(.blue, lineWidth: 1)
)
}
.padding()
.background(.red)
}
}
}
I have a simple SwiftUI application with CoreData and two views. One view displays all "Place" objects. You can create new places and you can show the details for the place.
Inside the second view you can add "PlaceItem"s to a place.
The problem is that, once a new "PlaceItem" is added to the viewContext, the @NSFetchRequest seems to forget about its additional predicates, which I set in onAppear. Then every place item is shown inside the details view. Once I update the predicate manually (the refresh button), only the items from the selected place are visible again.
Any idea how this can be fixed? Here's the code for my two views:
struct PlaceView: View {
@FetchRequest(sortDescriptors: []) private var places: FetchedResults<Place>
@Environment(\.managedObjectContext) private var viewContext
var body: some View {
NavigationView {
List(places) { place in
NavigationLink {
PlaceItemsView(place: place)
} label: {
Text(place.name ?? "")
}
}
}
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button {
let place = Place(context: viewContext)
place.name = NSUUID().uuidString
try! viewContext.save()
} label: {
Label("Add", systemImage: "plus")
}
}
}
.navigationTitle("Places")
}
}
struct PlaceItemsView: View {
@ObservedObject var place: Place
@FetchRequest(sortDescriptors: []) private var items: FetchedResults<PlaceItem>
@Environment(\.managedObjectContext) private var viewContext
func updatePredicate() {
items.nsPredicate = NSPredicate(format: "place == %@", place)
}
var body: some View {
NavigationView {
List(items) { item in
Text(item.name ?? "");
}
}
.onAppear(perform: updatePredicate)
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button {
let item = PlaceItem(context: viewContext)
item.place = place
item.name = NSUUID().uuidString
try! viewContext.save()
} label: {
Label("Add", systemImage: "plus")
}
}
ToolbarItem(placement: .navigationBarLeading) {
Button(action: updatePredicate) {
Label("Refresh", systemImage: "arrow.clockwise")
}
}
}
.navigationTitle(place.name ?? "")
}
}
struct ContentView: View {
@Environment(\.managedObjectContext) private var viewContext
var body: some View {
NavigationView {
PlaceView()
}
}
}
Thanks!
Hi, I'm embedding the QLPreviewController in a UIViewControllerRepresentable. When I view .usdz models I don't see the AR/Object selector at the top, nor the sharing button. I have tried presenting modally with a .sheet modifier and had the same result. What do I need to do to get the controls? Thanks, code attached.
Code
Spiff
Hi, I'm trying to make a weather menu bar app, and I want to have it so that the icon of the app in the menu changes with the actual weather, but the icon isn't showing up. There is still a space in the menu bar where I can click and open the app, it's just that the icon has disappeared. Any ideas to fix it?
Hello,
It's impossible to manage hit area for textfield and it's already too small by default (detected with Accessibility Inspector).
I'm tried to force with modifier "frame(minHeight: xxx)", the component change the height but the hit area is still in same size.
Have to tips to fix this issue?
Hi,
In a Mac Catalyst app, I need to allow the user insert a passcode using a UITextField.
The field is used to insert a one time passcode and I want to keep the content hidden. For this reason I set the isSecureTextEntry property to true.
passcodeTextField.isSecureTextEntry = true
By doing this, a button to allow the user to pick a password from the keychain is displayed:
This option in my case should not appear because the password is a one time password that change every time. For that reason I set the textContentType to oneTimeCode.
passcodeTextField.textContentType = .oneTimeCode
This actually removes the password button, but introduce something weird. If the user type something and then delete everything, a big empty box appear under the field:
I have no idea what this box is and why it appears.
Does anyone know why it appears and how I can remove it?
Thank you
I have a NSRulerView with a vertical orientation. It works fine from macOS 10.13 to 11.x.
In macOS Monterey (12.2.1 here), the ruler view is not receiving drawHashMarksAndLabelsInRect: messages when the associated NSTextView is scrolled vertically.
When the parent NSScrollView is resized, the ruler view is correctly refreshed on all macOS versions.
[Q] Is it a known bug in macOS Monterey?
.commandsRemoved() does not work for the Window and WindowGroup scenes if it’s the primary group (first one).
Then I tried to add new menu using the code
.commands {
CommandGroup(replacing: .newItem) {
Button("New Document") {
newDocument { TestDocument() }
}
.keyboardShortcut("n")
}
But app crashed with error " Expected subclass override"
The test app is a document-based app, with a welcome window using the new Window scene.
It works on Monterey, but not work on Ventura.
struct ContentView: View {
@FocusState private var focus: FocusableElement?
@FocusedValue(\.focusedElement) var focusElement
var body: some View {
VStack(spacing: 30) {
HStack {
GroupBox {
Circle()
.focusable()
.focused($focus, equals: .circle)
.focusedValue(\.focusedElement, .circle)
.frame(width: 100, height: 100)
.padding()
Text(focus == .circle ? "Selected" : "Not selected")
}
.onTapGesture {
focus = .circle
}
GroupBox {
Rectangle()
.focusable()
.focused($focus, equals: .rectangle)
.focusedValue(\.focusedElement, .rectangle)
.frame(width: 100, height: 100)
.padding()
Text(focus == .rectangle ? "Selected" : "Not selected")
}
}
.onTapGesture {
focus = .rectangle
}
Text("Focused Element: \(focusElement?.rawValue ?? "None")")
}
.padding()
.frame(width: 500, height: 300)
}
}
enum FocusableElement: Equatable, Hashable {
case rectangle
case circle
}
enum Selection: String, Hashable {
case none
case rectangle
case circle
}
extension FocusedValues {
struct FocusedElement: FocusedValueKey {
typealias Value = Selection
}
var focusedElement: FocusedElement.Value? {
get { self[FocusedElement.self] }
set {
self[FocusedElement.self] = newValue
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Dear All,
Recent updates in SwiftUI allow to add scope bars just beneath the search bar. Those are limited in space, though.
How does one implement a scrollable filter as is seen in the Apple’s own Developer app?
When I tried this, the app crashed immediately with a requirement to use NSTextContentStorage subclass
In TextKit 1, I can override drawBackground(forGlyphRange:at:) in NSLayoutManager to do custom background drawing. However, I'm not too sure what the designated way of doing background drawing is in TextKit 2.
One thing I've tried is to do custom drawing in my own CALayer that's used in the configureRenderingSurface delegate callback, but I'm unsure if we are suppose to use this API and steal the textViewportLayoutController.delegate away from _UITextLayoutcanvasView?
struct ContentView: View {
@State var isPresented = false
var body: some View {
Button {
isPresented.toggle()
} label: {
Text("Button")
}
.sheet(isPresented: $isPresented) {
SubView()
}
}
}
struct SubView: View {
@State var text = ""
var body: some View {
NavigationStack {
TextEditor(text: $text)
.toolbar {
ToolbarItemGroup(placement: .bottomBar) {
Button("Click") {
}
}
ToolbarItemGroup(placement: .keyboard) {
Button("Click") {
}
}
}
}
}
}