Post

Replies

Boosts

Views

Activity

GeometryReader problem
I'm adding Admob ads to my app, and Admob needs to know the width of the view, so I'm using GeometryReader for that. To prevent GeometryReader from grabbing screen space, I've wrapped the main view in GeometryReader { }. I then use geometry.size.width in my call to the adView. This all works fine. I have two main screens where I show ads, and they both work, until I rotate the device. Then the app crashes! If I comment out the GeometryReader code and pass a fixed value to the ad view, I can rotate the device with no fear of a crash. My question is: Do I have to accept that GeometryReader will crash the app when it's rotated, or is there another, stable way to get view dimensions?
3
0
187
Dec ’24
Advertising supported apps
Apple is pushing to use AdAttributionKit, but when I look at various ad networks, their sample code isn't using it. I'd like to find a simple example using a banner add and a third party ad network like admob. Also, I'm not clear on what post backs really do, or if I need them at all. If anyone can point me to clear documentation that is up to date, that would be great!
0
0
157
Dec ’24
Xcode / Swift(UI/Data) / Appstoreconnect Oddities
I’ve noticed a good number of strange problems in the IOS development process, so I’m going to track them here. If they’re resolved at some point, I’ll note it. At least in my first attempt, letting Appleconnect build my code resulted in a build with no errors that could not be submitted for review. The solution for me was to build from Xcode. It took a while to stumble on that, so if you have problems with one way, try the other. Xcode doesn’t show Info.plist by default. This is a particularly nasty bug that caused a great deal of trouble, being the biggest reason I had so much trouble getting my first app submitted for review. The only way I found to get around it was to make a small change to one of the items under the Info tab under the project name/icon in Xcode. Then, the Info.plist showed up! SwiftUI and SwiftData are siloed off from each other, so if you have a list, the view is controlled by SwiftUI. This means that if a user moves an item in a list, SwiftData is not informed. If the user quits the app, the order will revert to the last saved version! So you must resort to tracking the order in your code and adjusting your query accordingly.
1
0
186
Dec ’24
Infinite view loop
If I add items at the root level, this code works, but if I attempt to add a child to any item, it runs an infinite loop where it goes from the AddItemView back to the SubItemView and starts all over. I suspect it has something to do with the Predicate in SubItemView, but the debugger is crap, so I'm just guessing. Minimal code: @Model final class Item { var id: String var name: String var children: [Item] = [] @Relationship(deleteRule: .cascade) var parent: Item? init(name: String, parent: Item?, id: String = UUID().uuidString) { self.name = name self.parent = parent self.id = id } } struct ContentView: View { @Environment(\.modelContext) private var modelContext @Query( filter: #Predicate<Item> { item in item.parent == nil }, sort: \Item.name ) public var rootItems: [Item] var body: some View { NavigationStack { List { ForEach(rootItems) { item in HStack { NavigationLink ( destination: SubItemView(parent: item)) { Text(item.name) } } } } .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { NavigationLink(destination: AddItemView(itemParent: nil)) { Text("Add To Do") } } } } } } struct SubItemView: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) private var modelContext @State var parent: Item @State private var todo: String = "" @State var selectedDate = Date() @State var showPicker: Bool = false @Query var children: [Item] init(parent: Item) { self.parent = parent let parentID = parent.id _children = Query(filter: #Predicate<Item> { $0.parent.flatMap(\.id) == parentID && $0.parent.flatMap(\.id) != nil }, sort: \Item.name ) } var body: some View { Form { LabeledContent { TextField("Name", text: $parent.name) } label: { Text("Name:") } } Text("Parent: \(parent.name)\n") NavigationStack { Text("Child count: \(children.count)") List(children) { child in HStack { if(child.children.isEmpty) { Text(child.name) NavigationLink ( destination: SubItemView(parent: child)) { Text("").foregroundColor(.white).background(Color.blue) } .opacity(0) .background( Text("") ) } else { Text(child.name) NavigationLink(destination: SubItemView(parent: child)) { Text("") } } } } } .navigationTitle("Sub Items") .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { NavigationLink(destination: AddItemView(itemParent: parent)) { Text("Add To Do") } } ToolbarItem { Button("Save") { try? modelContext.save() dismiss() } } } } } struct AddItemView: View { @Environment(\.dismiss) private var dismiss @Environment(\.modelContext) private var context @State var itemParent: Item? @State private var name = "" @State private var showWarning: Bool = false @State var child = Item(name: "", parent: nil) var body: some View { NavigationStack { Form { LabeledContent { TextField("Item", text: $name) } label: { Text("Todo:") } } .navigationTitle("Add New Item") .toolbar { Button("Save") { let tmp = Item(name: name, parent: itemParent) if(itemParent != nil) { itemParent!.children.append(tmp) } context.insert(tmp) try? context.save() dismiss() } } } } }
4
0
310
Nov ’24
Linked list?
The code below works, in that it successfully creates an item and attached it to the parent item, but the parent view doesn't show the new child until you navigate away from the parent and then back to it. Parent: Child1 Child2 // Add Child 3 and this does not refresh when returning through the dismiss() call, but if I navigate to the grand Parent, and then back to the Parent, Child 3 is there. Any ideas? NavigationStack { Form { LabeledContent { TextField("Item", text: $name) } label: { Text("Item:") } } .navigationTitle("Add New Item") .toolbar { Button("Save") { var tmp = Item(timestamp: Date(), name: name, parent: itemParent) if(itemParent != nil) { itemParent!.children.append(tmp) } context.insert(tmp) try? context.save() dismiss() } } }
2
0
346
Nov ’24
ScrollViewReader
I'd like to use ScrollViewReader, but on a list of static text that has formatting such as font colors and bold text. Essentially, my list has a bunch of: Text("some text ") + Text(" and more text").fontWeight(.bold).foregroundStyle(boldColor) Switching to AttributedString would be a pain, and I'm not so sure ScrollViewReader is working correctly. It seems like there are a lot of bugs reports about it. Plus, do we really need a separate string format, just to have proper formatting? Really? Is there another version I'm missing? One that can scroll to anchor points that I could set?
0
0
210
Nov ’24
AVSpeechUtterance problem
I see this error in the debugger: #FactoryInstall Unable to query results, error: 5 IPCAUClient.cpp:129 IPCAUClient: bundle display name is nil Error in destroying pipe Error Domain=NSCocoaErrorDomain Code=4099 "The connection from pid 5476 on anonymousListener or serviceListener was invalidated from this process." UserInfo={NSDebugDescription=The connection from pid 5476 on anonymousListener or serviceListener was invalidated from this process.} on this function: func speakItem() { let utterance = AVSpeechUtterance(string: item.toString()) utterance.voice = AVSpeechSynthesisVoice(language: "en-GB") try? AVAudioSession.sharedInstance().setCategory(.playback) utterance.rate = 0.3 let synthesizer = AVSpeechSynthesizer() synthesizer.speak(utterance) } When running without the debugger, it will (usually) speak once, then it won't speak unless I tap the button that calls this function many times. I know AVSpeech has problems that Apple is long aware of, but I'm wondering if anyone has a work around. I was thinking there might be a way to call the destructor for AVSpeechUtterance and generate a new object each time speech is needed, but utterance.deinit() shows: "Deinitializers cannot be accessed"
0
1
256
Nov ’24
unexpected nil
` init() { nextOrder = self.AllItems.map{$0.order}.max() if nextOrder == nil { nextOrder = 0 } nextOrder! += 1 // <--- Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value } ` I have to say, Swift is great - when it works!
8
0
546
Nov ’24
onMove bug
I'm not sure where to report this, so here it is. If you have a list of items and you make them clickable and movable, moving one or more items in the list and then clicking will cause them to move. This is yet another reason that SwiftData needs to track onMove. Minimal reproducible code: // // ContentView.swift // exampleBug // // Create a new project. // Replace the default Item class with the one below, and replace ContentView with its class below // Run the app and add a few items a few seconds apart so you can tell them apart. // Drag an item to a new position in the list. // Click one of the checkboxes and watch the list positions change for no reason! // import SwiftUI import SwiftData @Model final class Item { var timestamp: Date var checkbox: Bool = false init(timestamp: Date) { self.timestamp = timestamp } } struct ContentView: View { @Environment(\.modelContext) private var modelContext @State private var editMode = EditMode.inactive @Query private var items: [Item] var body: some View { NavigationStack { List { ForEach(items) { item in HStack { Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard)) Button("", systemImage: item.checkbox ? "checkmark.circle.fill" : "circle") { item.checkbox.toggle() try? modelContext.save() } } } .onMove(perform: { indices, newOffset in var theItems = items theItems.move(fromOffsets: indices, toOffset: newOffset) }) } .environment(\.editMode, $editMode) .moveDisabled(false) .toolbar { ToolbarItem(placement: .navigationBarTrailing) { EditButton() } ToolbarItem { Button(action: addItem) { Label("Add Item", systemImage: "plus") } } } } } func addItem() { withAnimation { let newItem = Item(timestamp: Date()) modelContext.insert(newItem) } } func deleteItems(offsets: IndexSet) { withAnimation { for index in offsets { modelContext.delete(items[index]) } } } } #Preview { ContentView() .modelContainer(for: Item.self, inMemory: true) } code-block
2
0
297
Nov ’24