Generic parameter 'C' could not be inferred - dictionary

I have a Data class as follows:
class Data: Hashable, Equatable {
var id: Int = 0
var name: String = ""
var date: Date = Date()
var paymentStatus: Bool = false
static func == (lhs: Data, rhs: Data) -> Bool {
return lhs.id ==
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
var data1: Data {
let data = Data()
data.id = 1
data.name = "John"
data.date = Calendar.current.date(byAdding: DateComponents(day: -6), to: Date())!
data.paymentStatus = true
return data
}
var data2: Data {
let data = Data()
data.id = 2
data.name = "Peter"
data.date = Date()
data.paymentStatus = false
return data
}
I’m trying to display the data in sections as follows:
struct ContentView: View {
var data: [Data] = [data1, data2]
var body: some View {
List {
ForEach(groupByDate(data), id: \.self) { studentsInMonth in
Section(header:Text(Date(), style: .date)) {
ForEach(data, id:\.self) { item in
HStack {
Text(item.name)
padding()
Text(item.date, style: .time)
if(item.paymentStatus == false) {
Image(systemName: "person.fill.questionmark")
.foregroundColor(Color.red)
} else {
Image(systemName: "banknote")
.foregroundColor(Color.green)
}
}
} // ForEach ends here...
} // section ends here
} // ForEach ends here
} // List ends here
}
}
func groupByDate(_ data: [Data]) -> [Date: [Data]] {
let empty: [Date: [Data]] = [:]
return data.reduce(into: empty) { acc, cur in
let components = Calendar.current.dateComponents([.year, .month], from: cur.date)
let date = Calendar.current.date(from: components)!
let existing = acc[date] ?? []
acc[date] = existing + [cur]
}
}
Not sure what mistake I’m making, but its throwing two errors:
Cannot convert value of type ‘[Date:[Data]]’ to expected argument type
Generic parameter ‘C’ could not be inferred
Appreciate any help

Right now, you're trying to iterate through a Dictionary using ForEach, which doesn't work -- ForEach expects a RandomAccessCollection, which is most often, an Array.
Instead, you can iterate over just the keys of the Dictionary.
struct ContentView: View {
var data: [Data] = [data1, data2]
var body: some View {
let grouped = groupByDate(data)
List {
ForEach(Array(grouped.keys), id: \.self) { key in
let studentsInMonth = grouped[key]!
Section(header:Text(key, style: .date)) {
ForEach(studentsInMonth, id:\.self) { item in
HStack {
Text(item.name)
padding()
Text(item.date, style: .time)
if(item.paymentStatus == false) {
Image(systemName: "person.fill.questionmark")
.foregroundColor(Color.red)
} else {
Image(systemName: "banknote")
.foregroundColor(Color.green)
}
}
} // ForEach ends here...
} // section ends here
} // ForEach ends here
} // List ends here
}
}
Although the above works, I'd consider refactoring your groupByDate function so that it returns an Array directly instead of having to go through the above transformations.
Also, unrelated to your question, but right now, in your header, you're displaying a date -- you get just the year and month, but then display it as a full date, so the header says "January 1, 2022" for all the January dates. You probably want to refactor this to just show the month and year.

Related

Generic parameter 'Success' could not be inferred; Key path value type '_' cannot be converted to contextual type '_'; Cannot find 'Response' in scope

I think this might be the last push for my project of mobile GitHub query repository search, but I get 3 errors I cannot find out how to cope with.
The code:
import SwiftUI
import Combine
struct Root: Codable {
let items: [Item]
enum CodingKeys: String, CodingKey {
case items
}
}
struct Item: Identifiable, Codable {
let id: Int
let urlCode: String
let fullName: String
enum CodingKeys: String, CodingKey {
case id
case urlCode = "url"
case fullName = "full_name"
}
}
private final class ContentViewState: ObservableObject {
#Published var isLoading = false
#Published var query = ""
#Published var stuff = [String]()
private var subscription: AnyCancellable?
func fetchRepos(query: String) {
isLoading = true
subscription = Just("test")
.delay(for: 2, scheduler: RunLoop.main)
.sink(receiveValue: {[weak self] (title: String) in
self?.isLoading = false
self?.stuff.append(title)
})
}
}
struct ContentView: View {
#StateObject private var state = ContentViewState()
#State private var items = [Item]()
var body: some View {
VStack {
if state.isLoading {
ProgressView()
} else {
HStack {
TextField("Enter search", text: $state.query)
Button("Search") {
state.fetchRepos(query: state.query)
}
}
List(items, id: \.id) { item in
VStack(alignment: .leading) {
Text(item.fullName).font(.headline)
Text(item.urlCode)
}
}.task {
await loadData()
}
}
}
}
func loadData() async {
guard let url = URL(string: "https://api.github.com/search/repositories?q=" + state.query + "&per_page=20") else
{
print("Invalid URL")
return
}
do {
let (data, _) = try await URLSession.shared.data(from: url)
if let decodedResponse = try? JSONDecoder().decode(Root.self, from: data) {
items = decodedResponse.items
}
} catch {
print("Invalid data ")
}
}
}
The errors:
"Generic parameter 'Success' could not be inferred" on line:
TextField("Enter search", text: $state.query)
"Key path value type '' cannot be converted to contextual type ''" on line:
await loadData()
}
}
"Cannot find 'Response' in scope" on line:
} catch {
print("Invalid data ")
}
}
}
Please help :)
The answer was to move the code to another file, change its structure a bit and everything works fine now!

Trying to show fetched firebase data on profile view SwiftUI

I'm trying to show the data I fetched from my Firebase database. I tried creating #State var variables and add them to my function but it didn't work. I tried printing my function output in a button to print it to console and it works. I just don't know how to show them in my view my code
import SwiftUI
import Firebase
struct ProfileView: View {
var body: some View {
VStack {
Button(action: {
profilef()
}) {
Text("hello")
}
HStack {
Button(action: {
try! Auth.auth().signOut()
UserDefaults.standard.set(false, forKey: "status")
NotificationCenter.default.post(name: NSNotification.Name("statusChange"), object: nil)
}) {
Text("Logout")
}
}
}
}
func profilef() {
let userID = Auth.auth().currentUser?.uid
let ref = Database.database().reference()
ref.child("UserInfo").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
let value = snapshot.value as? [String : AnyObject]
let name = value?["fullName"] as? String ?? ""
print(name)
// ...
}) { error in
print(error.localizedDescription)
}
}
}
Just create a #State variable, which contains the name. If your function changes that variable, your view will updates.
struct profile: View {
#State var name : String = ""
var body: some View {
Text("Hello " + self.name)
And then in your function, instead of printing you will assign it to your state.
let name = value?["fullName"] as? String ?? ""
print(name)
self.name = name
That should work. I do not have an example with Firebase at the moment, so I can not test it. If it is not working, please describe the behavior.
Adding an #State property profileName and assigning it in the network request function will work after tapping the Button.
// ProfileView.swift
//
//
// Created by Shahin Bararesh on 2020-09-07.
//
import SwiftUI
import Firebase
struct ProfileView: View {
#State var profileName: String = ""
var body: some View {
VStack {
Button(action: {
profilef()
}) {
Text(profileName)
}
HStack {
Button(action: {
try! Auth.auth().signOut()
UserDefaults.standard.set(false, forKey: "status")
NotificationCenter.default.post(name: NSNotification.Name("statusChange"), object: nil)
}) {
Text("Logout")
}
}
}
}
func profilef() {
let userID = Auth.auth().currentUser?.uid
let ref = Database.database().reference()
ref.child("UserInfo").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
// Get user value
let value = snapshot.value as? [String : AnyObject]
let name = value?["fullName"] as? String ?? ""
self.profileName = name
// ...
}) { error in
print(error.localizedDescription)
}
}
}

SWIFTUI Call Key Dictionary not work with the error: 'Subscript index of type '() -> Bool' in a key path must be Hashable'

I have this view:
import SwiftUI
struct SectionView1: View {
let dateStr:String
#Binding var isSectionView:Bool
var body: some View {
HStack {
Button(action: {
self.isSectionView.toggle()
}) {
Image(systemName: isSectionView ? "chevron.down.circle" : "chevron.right.circle")
}
Text("Media del \(dateStr)")
}
}
}
which will be called from view:
import SwiftUI
import Photos
struct MediaView: View {
let geoFolder:GeoFolderCD
#State private var assetsForDate = [String :[PHAsset]]()
#State private var isSectionViewArray:[String:Bool] = [:]
var body: some View {
List {
ForEach(assetsForDate.keys.sorted(by: > ), id: \.self) { dateStr in
Section {
SectionView1(dateStr: dateStr,
isSectionView: self.$isSectionViewArray[dateStr, default: true])
}
}
}
.onAppear {
self.assetsForDate = FetchMediaUtility().fetchGeoFolderAssetsForDate(geoFolder: geoFolderStruct, numAssets: numMediaToFetch)
for dateStr in self.assetsForDate.keys.sorted() {
self.isSectionViewArray[dateStr] = true
}
}
}
}
but I have the error: Subscript index of type '() -> Bool' in a key path must be Hashable in isSectionView: self.$isSectionViewArray[dateStr, default: true]
Why isSectionViewArray:[String:Bool] = [:] is not Hasbable?
How can modify the code for work?
If I remove, in SectionView, #Binding var isSectionView:Bool, the code work fine, or if I set, from SectionView, #Binding var isSectionViewArray:[String:Bool] = [:], the code work fine.
You can write your own binding with the below code and it should work
var body: some View {
List {
ForEach(assetsForDate.keys.sorted(by: > ), id: \.self) { dateStr in
let value = Binding<Bool>(get: { () -> Bool in
return self.isSectionViewArray[dateStr, default: true]
}) { (value) in
}
Section {
SectionView1(dateStr: dateStr,
isSectionView: value)
}
}
}
.onAppear {
self.assetsForDate = FetchMediaUtility().fetchGeoFolderAssetsForDate(geoFolder: geoFolderStruct, numAssets: numMediaToFetch)
for dateStr in self.assetsForDate.keys.sorted() {
self.isSectionViewArray[dateStr] = true
}
}
}

Data not showing in Swiftui using Firebase

Can someone tell me what I am doing wrong? I am using Swiftui and firebase database. I am not seeing any error or any data on the screen. I did install the Pods and checked the security rules as well in console. I tried couple other methods, but this was exactly same from youtube tutorials except the collection name and fields.
import SwiftUI
import Firebase
struct Calories: View {
#ObservedObject var data = getData()
var body: some View {
NavigationView{
ZStack(alignment: .top){
GeometryReader{_ in
// Home View....
Text("Home")
}.background(Color("Color").edgesIgnoringSafeArea(.all))
CustomSearchBar(data: self.$data.datas).padding(.top)
}.navigationBarTitle("")
.navigationBarHidden(true)
}
}
}
struct Calories_Previews: PreviewProvider {
static var previews: some View {
Calories()
}
}
struct CustomSearchBar : View {
#State var txt = ""
#Binding var data : [dataType]
var body : some View{
VStack(spacing: 0){
HStack{
TextField("Search", text: self.$txt)
if self.txt != ""{
Button(action: {
self.txt = ""
}) {
Text("Cancel")
}
.foregroundColor(.black)
}
}.padding()
if self.txt != ""{
if self.data.filter({$0.item.lowercased().contains(self.txt.lowercased())}).count == 0{
Text("No Results Found").foregroundColor(Color.black.opacity(0.5)).padding()
}
else{
List(self.data.filter{$0.item.lowercased().contains(self.txt.lowercased())}){i in
NavigationLink(destination: Detail(data: i)) {
Text(i.item)
}
}.frame(height: UIScreen.main.bounds.height / 5)
}
}
}.background(Color.white)
.padding()
}
}
class getData : ObservableObject{
#Published var datas = [dataType]()
init() {
let db = Firestore.firestore()
db.collection("HSCal").getDocuments { (snap, err) in
if err != nil{
print((err?.localizedDescription)!)
return
}
for i in snap!.documents{
let id = i.documentID
let item = i.get("item") as! String
let cal = i.get("cal") as! String
self.datas.append(dataType(id: id, item: item, cal: cal))
}
}
}
}
struct dataType : Identifiable {
var id : String
var item : String
var cal : String
}
struct Detail : View {
var data : dataType
var body : some View{
Text(data.item)
}
}
did you put app bundle?
try in
struct Calories: View {
#EnvironmentObject var List: getData()
....
}
call
Calories().environmentObject(DataList)
declare somewhere
var DataList = getData()

ObservedObject only passes its default value; not its assigned value. Why?

Scenario: Attempting to broadcast a variable value via an ObservableObject.
Problem: I'm only getting the default value; not the assigned value.
Here's the origin.
Button #1 starts a function to get data.
Button #2 retrieves the ObservedObject's revised value
I removed some of the vestigial code to make the presentation simpler:
struct ContentView: View {
#ObservedObject var networkManager = NetworkManager()
let fontCustom = Font.custom("Noteworthy", size: 23.0)
var body: some View {
ZStack {
// ...
// ...
HStack {
Button(
action: {
NetworkManager().getCalculatorIDs()
},
label: {
Text("1")
}
)
Button(
action: {
self.calculator.calculate("2");
print(self.networkManager.calculationID) // stop and check.
},
label: { Text("2") }
)
// ...
// ...
}
}
So I tap Button #1 then tap Button #2 to check if the ObservedObject has the generated id value.
I'm expecting an alphanumeric id value in the print().
Instead, I got the original value:
Royal Turkey
(lldb)
Here's the ObservableObject:
struct CalculationIdentifier: Decodable {
let id: String
let tokens: [String]
}
class NetworkManager: ObservableObject {
#Published var calculationID = "Royal Turkey"
#Published var isAlert = false
#Published var name = "Ric Lee"
let calculations = "https://calculator-frontend-challenge.herokuapp.com/Calculations"
func getCalculatorIDs() {
let urlRequest = URLRequest(url: URL(string: calculations)!)
let configuration = URLSessionConfiguration.ephemeral
let task = URLSession(configuration: configuration).dataTask(with: urlRequest) { data, _, error in
DispatchQueue.main.async {
do {
let result = try JSONDecoder().decode([CalculationIdentifier].self, from: data!)
if !result.isEmpty {
self.calculationID = (result[0] as CalculationIdentifier).id
print("Inside do{}. result = \(result)")
self.isAlert = true
} else {
print(#function, "Line:", #line, ": No Result")
}
} catch {
print(error)
}
}
}
task.resume()
}
}
BTW: Here's the local console output, the string value of 'id' should have been passed to the host as an ObservedObject value:
Inside do{}. result = [RicCalculator2.CalculationIdentifier(id: "d3dd3b1e-d9f6-4593-8c85-b8fd3d018383", tokens: [])]
So I do have a bona fide id value to send.
Why only the original value?
What am I missing?
...do I need to do a 'send' or something?
This
A. #ObservedObject var networkManager = NetworkManager()
and this
B. NetworkManager().getCalculatorIDs()
in your code are different objects, ie. you create one object as member, then other object on the stack, which does something, and then ask first object to return something - naturally if returns what it has on initialise.
Probably you assumed in case B
self.networkManager.getCalculatorIDs()

Resources