Can I show a sheet using a String?
Please let me know if there's a way around it.
#State var selectedContactInfo: String?
.sheet(item: $selectedContactInfo){ item in MessageView(recipient: selectedContactInfo!) }
I'm receiving this error:
Instance method 'sheet(item:onDismiss:content:)' requires that
'String' conform to 'Identifiable'
String could become Identifiable
Its id could be self because String is Hashable
extension String: Identifiable {
public var id: String {self}
}
Related
I don't know how to write ForEach in Array in struct by SwiftUI.
struct Group: Identifiable,Decodable{
#DocumentID var id: String?
var name: String
var members: [[String:String]]
}
I want to display member's array by using ForEach.
#ObservedObject var groupVM: GroupViewModel
var body: some View {
NavigationView {
List{
ScrollView{
LazyVStack(alignment: .leading){
ForEach(groupVM.group.members){ member in
groupMemberCell()
}
}
}
}
}
}
I got this error Referencing initializer 'init(_:content:)' on 'ForEach' requires that '[String : String]' conform to 'Identifiable'.
Please tell me how to write the right way.
This is because the value for members (of type [[String: String]]) does not automatically conform to Identifiable.
It depends on your model as to how each individual member (with data [String: String]) needs to be identified, as it's not clear from this dictionary how you would do this (a dictionary is a bunch of keys and values for each member, so how do we know which member is which based off this data?).
I'd suggest modelling each member as its own object and include a field that allows you to uniquely identify each member (such as having an id for each member, which could be their user id in your application for example).
struct Member: Identifiable, Decodable {
var id: String
var data: [String: String]
}
Your group would then look like:
struct Group: Identifiable, Decodable {
#DocumentID var id: String?
var name: String
var members: [Member]
}
I am trying to practice mapping custom objects using swift & replace all manual mapping by using Codable. This concept is new to me but seems very worthwhile. In this project I want to fetch the user and make sure that all their data is stored in their User Document on firebase (including the custom object 'FavouriteItems'.
My User Model struct is:
import SwiftUI
import FirebaseFirestoreSwift
struct UserModel: Identifiable, Codable{
#DocumentID var id: String?
var username : String
var pic : String
var bio: String
var uid : String
var isVerified: Bool
var favouriteItems: [FavouriteItems]
}
My struct for an Item is:
import SwiftUI
import FirebaseFirestoreSwift
import Firebase
struct Item: Identifiable, Codable {
#DocumentID var id: String?
var item_name: String
var item_type: String
var item_image: String
var item_details: String
var item_uid : String
var didFavourite: Bool? = false
var isFavourite: Bool = false
}
My struct for FavouriteItems is:
import SwiftUI
import FirebaseFirestoreSwift
//MARK: Make Hashable (See Tag Example)?
struct FavouriteItems: Identifiable, Codable {
#DocumentID var id: String?
var item: Item
}
My fetch user function is (edited):
func fetchUser(uid: String, completion: #escaping (UserModel) -> ()){
let db = Firestore.firestore()
let docRef = db.collection("Users").document(uid).getDocument(as: UserModel.self) { result in
switch result {
case .success(let user):
// A `UserModel` value was successfully initialized from the DocumentSnapshot.
print("UserModel: \(user)")
DispatchQueue.main.async {
completion(user)
}
case .failure(let error):
// A `UserModel` value could not be initialized from the DocumentSnapshot.
print("Error decoding UserModel: \(error)")
// handle errors todo
}
}
}
I am getting errors in the fetchUser code including:
Cannot convert value of type 'UserModel.Type' to expected argument type 'FirestoreSource'
Contextual closure type '(DocumentSnapshot?, Error?) -> Void' expects 2 arguments, but 1 was used in closure body
Incorrect argument label in call (have 'as:_:', expected 'source:completion:')
All of these errors occur on the line:
let docRef = db.collection("Users").document(uid).getDocument(as: UserModel.self) { result in
Here is my Podfile:
I have a User object
#objc(User)
public class User: NSManagedObject {
#NSManaged public var firstname: String
#NSManaged public var lastname: String
#NSManaged public var country: String
#NSManaged public var friends: NSSet // of User objects
var full: String {
firstname + " " + lastname
}
var friendsArray: [User] {
friends.allObjects as? [User] ?? []
}
}
and at some point I want to map a large array of users (80k objects) to an array of View models
struct ItemViewModel: Hashable {
let id: UUID
let friendsName: [String]
}
Without lazy it takes a long time, so I have opted for the usag of lazy:
func prepareViewModel(users: [User]) -> [ItemViewModel] {
users.map { user in
let friendsName = user.friendsArray.lazy.filter{["en", "fr"].contains($0.country)}.map(\.full)
return ItemViewModel(id: UUID(), friendsName: friendsName)
}
}
But I get an error:
Cannot convert value of type 'LazyMapSequence<LazyFilterSequence<LazySequence<[User]>.Elements>.Elements, String>'
(aka 'LazyMapSequence<LazyFilterSequence<Array<User>>, String>') to expected argument type '[String]'
It makes sense because now the friends names array will be processed lazily later. I have tried to convert the view model struct to hold:
struct ItemViewModel: Hashable {
let id: UUID
let friendsName: LazyMapSequence<LazyFilterSequence<[User]>, String>
}
But now it's not Hashable is there a way to keep the auto-conformance to Hashable when using LazyMapSequence<LazyFilterSequence<[User]>, String> as type for ItemViewModel and any tips on how to improve performance of logic
I have the following code which represents a Hockey Stick and some information about it. I have an issue where the stick isn't conforming to Decodable. I understand that every type used in the struct needs to also be codeable, and they are. For some reason however the "var conditions" line causes the error that I am unsure how to fix. Thank you!
enum StickLocation: Int, Codable, Hashable, CaseIterable {
case handle, mid, bottom
}
enum StickCondition: Int, Codable, Hashable, CaseIterable {
case pristine, scuffed, damaged, broken
}
struct HockeyStick: Identifiable, Codable {
var barcode: Int
var brand: String
var conditions: [StickLocation:(condition:StickCondition, note:String?)] // Offending line
var checkouts: [CheckoutInfo]
var dateAdded: Date
var dateRemoved: Date?
// Conform to Identifiable.
var id: Int {
return self.barcode
}
// If the stick was never removed then its in service.
var inService: Bool {
return self.dateRemoved == nil
}
}
The value type of your conditions dictionary is (StickCondition, String?), which is a tuple. Tuples are not Decodable/Encodable, and you cannot make them conform to protocols, so to fix this I recommend you make a new struct to replace the tuple like this:
enum StickLocation: Int, Codable, Hashable, CaseIterable {
case handle, mid, bottom
}
enum StickCondition: Int, Codable, Hashable, CaseIterable {
case pristine, scuffed, damaged, broken
}
struct StickConditionWithNote: Codable, Hashable {
var condition: StickCondition
var note: String?
}
struct HockeyStick: Identifiable, Codable {
var barcode: Int
var brand: String
var conditions: [StickLocation: StickConditionWithNote]
var checkouts: [CheckoutInfo]
var dateAdded: Date
var dateRemoved: Date?
// Conform to Identifiable.
var id: Int {
return self.barcode
}
// If the stick was never removed then its in service.
var inService: Bool {
return self.dateRemoved == nil
}
}
I'm following every guide I've seen online to bring in the managed object to the SwiftUI scene with environment and then run a #FetchRequest in the scene, all of it works great.
I can use that result to populate the value of a picker
Heres what I have
CoreData Object
public class CD_LookupData: NSManagedObject,Identifiable {}
extension CD_LookupData {
#nonobjc public class func fetchRequest() -> NSFetchRequest<CD_LookupData> {
return NSFetchRequest<CD_LookupData>(entityName: "CD_LookupData")
}
#NSManaged public var lookluptable: String?
#NSManaged public var primarykeyid: String?
#NSManaged public var value: String?
}
SwiftUI View
struct LabledSelectBoxCD: View {
var label: String
var lookupdata: FetchedResults<CD_LookupData>
#Binding var value: Int
var body: some View
{
VStack(alignment: .leading)
{
Picker(selection: $value, label: Text(""))
{
ForEach(lookupdata, id: \.primarykeyid)
{ data in
Text(data.value ?? "Unknown")
}
}
}
}
}
Its populates the picker with the values just fine but my default value never works and no value selected is saved.
If I try the same view with just an array of strings it works perfectly.
Any ideas on how I can get it to use the value of primarykeyid for the value of the picker?
Update:
#Binding var value: String
and
Text(data.value ?? "Unknown").tag(data.primarykeyid)
Don't make any changes
You need to make your value an optional String because that is what the type primaryKeyId is
#Binding var value: String?
And then you need a tag on each element of the picker to set the selection:
Text(data.value ?? "Unknown").tag(data.primaryKeyId)