Inexperienced "senior" coder here. Learning by imitation, but going relatively well. Keep rebuilding my App and it gets better with each iteration but I then get to the same stumbling block each time... the Product Category and the associated Picker that I am trying to implement.
In my latest iteration, I keep getting the following error in the Xcode Console when running my App in the simulator and going to the associated view:
Picker: the selection "nil" is invalid and does not have an associated tag, this will give undefined results.
I am trying to get a simple Category selection applied to a Product. The Category list is a Model/Array on its own.
@Model
class Category {
var name: String = ""
var products: [Product]?
init(
name: String
) {
self.name = name
self.products = []
}
}
@Model
class Product {
var name: String = ""
@Relationship(inverse: \Order.products)
var orders: [Order]?
// @Relationship(inverse: \Category.products)
var category: Category?
init(
name: String,
category: Category? = nil
) {
self.name = name
self.orders = []
self.category = category
}
}
I cannot select an item in the picker and it is not persisted in the Product record.
struct AddProductView: View {
@Environment(\.dismiss) private var dismiss
@Environment(\.modelContext) var context
@Environment(\.presentationMode) var presentationMode
@Query(sort: \Category.name) var categories: [Category]
@State private var name: String = ""
@State private var category: Category?
var body: some View {
NavigationStack {
Form {
TextField("New Product Name", text: $name)
VStack {
Section {
Picker("Choose a Category?", selection: $category) {
// Text("").tag("")
ForEach(categories, id:\.self) { category in
Text(category.name).tag(category.name)
}
}
}
}
}
.navigationTitle("New Product")
.navigationBarTitleDisplayMode(.large)
.toolbar {
ToolbarItem(placement: .topBarLeading) {
Button("Cancel") { dismiss() }
}
// MARK: Need to add data check on name field
ToolbarItem(placement: .topBarTrailing) {
Button("Save") {
let product = Product(name: name)
context.insert(product)
dismiss()
}
}
}
}
}
}
I must be doing something simple incorrectly, but I cannot see it.
My App is using SwiftData for persistence and is linked to iCloud.
Any thoughts, suggestions, or guidance, would be much appreciated.
Simon
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I have implemented filtering on two lists in my app but for some reason cannot get this, the third, to work at all.
Inexperienced coder so please go easy on me!
Any guidance, suggestions, or pearls of wisdom appreciated in advance.
Am looking to have the filter on the list in the SelectProductsView...
@Environment(\.dismiss) var dismiss
@Environment(\.modelContext) private var modelContext
@Query var products: [Product]
@Bindable var order: Order
@State private var formType: EditProductImageFormType?
@State private var newProduct = false
@State private var showProductDetail: Bool = false
var body: some View {
NavigationStack {
if products.isEmpty {
ContentUnavailableView("Add your first Product", systemImage: "takeoutbag.and.cup.and.straw")
} else {
VStack {
List {
ForEach(products) { product in
HStack {
Text(product.name)
Spacer ()
if let orderProducts = order.products {
if orderProducts.isEmpty {
Button {
addRemove(product)
} label: {
Image(systemName: "xmark.square")
}
} else {
Button {
addRemove(product)
} label: {
Image(systemName: orderProducts.contains(product) ? "checkmark.circle" : "xmark.square")
}
}
}
.swipeActions(edge: .leading, allowsFullSwipe: true) {
Button {
showProductDetail.toggle()
} label: {
Image(systemName: "questionmark.bubble")
}
.tint(.orange)
}
}
}
.navigationTitle("Select Products")
.navigationBarTitleDisplayMode(.large)
}
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button {
formType = .new
} label: {
Image(systemName: "plus.circle")
}
.sheet(item: $formType) { $0 }
}
ToolbarItem(placement: .topBarLeading) {
Button("\(Image(systemName: "chevron.backward")) \(order.name)") {
dismiss()
}
}
}
}
}
}
func addRemove(_ product: Product) {
if let orderProducts = order.products {
if orderProducts.isEmpty {
order.products?.append(product)
} else {
if orderProducts.contains(product),
let index = orderProducts.firstIndex(where: {$0.id == product.id}) {
order.products?.remove(at: index)
} else {
order.products?.append(product)
}
}
}
}
// Add product to Shopping List
func add(_ product: Product) {
if let orderProducts = order.products {
if orderProducts.isEmpty {
order.products?.append(product)
} else {
order.products?.append(product)
}
}
}
// Remove product from Shopping List
func remove(_ product: Product) {
if let orderProducts = order.products {
if orderProducts.contains(product),
let index = orderProducts.firstIndex(where: {$0.id == product.id}) {
order.products?.remove(at: index)
}
}
}
// Filter & Sort initialisation
init(sortOrder: ProductSortOrder2, filterString: String) {
let sortDescriptors: [SortDescriptor<Product>] = switch sortOrder {
case .name:
[SortDescriptor(\Product.name)]
}
let predicate = #Predicate<Product> { product in
product.name.localizedStandardContains(filterString)
|| filterString.isEmpty
}
_products = Query(filter: predicate, sort: sortDescriptors)
}
}
Am getting a "Return from initializer without initializing all stored properties" error in Xcode on teh second to last line, after the init
I am calling this View from the EditOrderView...
struct EditOrderView: View {
@Environment(\.dismiss) private var dismiss
let order: Order
@State private var dateAdded = Date.distantPast
@State private var filterText = ""
@State private var name = ""
@State private var showProducts = false
@State private var sortOrder = ProductSortOrder2.name
var body: some View {
NavigationStack {
ZStack {
// background
Color(.systemGroupedBackground)
.ignoresSafeArea(.all)
// content
VStack {
HStack {
Button("Add Products"))") {
showProducts.toggle()
}
.frame(maxWidth: .infinity, alignment: .center)
.sheet(isPresented: $showProducts) {
// replaced SelectProductsView(order: order)
SelectProductsView(sortOrder: ProductSortOrder2.name, filterString: filterText, order: order)
.searchable(text: $filterText, prompt: Text("Filter on Product name"))
}
}
if let products = order.products {
OrderProductsListView(order: order, products: products)
}
}
.toolbar {
if changed {
Button {
order.name = name
dismiss()
} label: {
Image(systemName: "checkmark.circle")
.imageScale(.large)
}
}
}
.onAppear {
name = order.name
}
}
}
}
var changed: Bool {
name != order.name
}
}
enum ProductSortOrder2: LocalizedStringResource, Identifiable, CaseIterable {
case name = "alphabetcially by Name"
var id: Self {
self
}
}
Code was rearranged to stay within 7000 charachters...
Hoping someone can point me in the right direction!
Simon
Young developer (old man though) need some advice/guidance on how to fault find iCloud issues.
A new App, pretty much started with iCloud setup, and I believe I have fulfilled all the necessary prerequisites. I have built other Apps that have worked find on iCloud, but this one simply refuses to work.
Error messages from the Console log file as follows:
=====>>
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _performSetupRequest:]_block_invoke(1223): <NSCloudKitMirroringDelegate: 0x2812901e0>: Failed to set up CloudKit integration for store: <NSSQLCore: 0x15bd05ee0> (URL: file:///var/mobile/Containers/Data/Application/EB138C06-5CE0-4FD2-BDCB-3087AF075ED6/Library/Application%20Support/MyShoppingLists.store)
<CKError 0x2823edf80: "Partial Failure" (2/1011); "Failed to modify some record zones"; uuid = 838326A8-25E4-4239-8FBF-F2604F1DEC3D; partial errors: {
com.apple.coredata.cloudkit.zone:defaultOwner = <CKError 0x2823ed230: "Server Rejected Request" (15/2001); "Request failed with http status code 500"; uuid = 838326A8-25E4-4239-8FBF-F2604F1DEC3D>
}>
<<=====>>
error: CoreData+CloudKit: NSCloudKitMirroringDelegate recoverFromError:](2303): <NSCloudKitMirroringDelegate: 0x2812901e0> - Attempting recovery from error: <CKError 0x2823edf80: "Partial Failure" (2/1011); "Failed to modify some record zones"; uuid = 838326A8-25E4-4239-8FBF-F2604F1DEC3D; partial errors: {
com.apple.coredata.cloudkit.zone:defaultOwner = <CKError 0x2823ed230: "Server Rejected Request" (15/2001); "Request failed with http status code 500"; uuid = 838326A8-25E4-4239-8FBF-F2604F1DEC3D>
}>
<<=====>>
error: CoreData+CloudKit: NSCloudKitMirroringDelegate _recoverFromError:withZoneIDs:forStore:inMonitor:](2604): <NSCloudKitMirroringDelegate: 0x2812901e0> - Failed to recover from error: CKErrorDomain:15
Recovery encountered the following error: (null):0
<<=====
Thanks in advance for any suggestions...