I am making this app, and I have a log page where you can see the times you logged earlier. I looped through my array of logs, but when I try to display a value from the array in the loop I get "The compiler is unable to type-check this expression in reasonable time; try breaking up the expression into distinct sub-expressions" error. Here is the code for the logView swift file, there are more files and if you need them I can give you them, thanks.
import SwiftUI
struct LogView: View {
@AppStorage("log") private var log: [String] = []
var body: some View {
List{
ForEach(0...log.count, id: \.self) { index in
if(index % 2 == 0 && index != 0){
NavigationLink{
Text("log detail view")
}label: {
HStack{
Text(index)
Spacer()
Text(index 1)
}
}
}
}
}
.navigationTitle("Log")
.listStyle(GroupedListStyle())
}
}
struct LogView_Previews: PreviewProvider {
static var previews: some View {
RatingView(rating: .constant(3))
}
}
Any and all tips are hugely appreciated, thanks!
CodePudding user response:
From your last comments, I understand you need something like the following. There is a struct LogItem that gets initialized with an id, the timestamp of the date/time of creation and a message. It also contains 2 functions to provide the the date and the time individually as formatted strings. Id, date and message are now var to match the Codable protocol.
In the LogView, there is a list nested within a NavigationView, so you can use NavigationLinks to a detail page (for that there is a new view LogDetailedView.
To add items to the array it is similar to the string array you used before, array has the function append, but instead of appending a string, you have to append an object of type LogItem. To show how it works I also added a button that creates a new instance of LogItem with the message "Log Message", it is just an example, you have to adjust it according to your needs.
//
// Log.swift
// Log
//
// Created by Sebastian on 23.08.22.
//
import SwiftUI
struct LogItem: Identifiable, Hashable, Codable {
var id = UUID().uuidString
var date = Date()
var message: String
func getDate() -> String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"
return dateFormatter.string(from: date)
}
func getTime() -> String {
let calendar = Calendar.current
let hour = calendar.component(.hour, from: date)
let minutes = calendar.component(.minute, from: date)
let seconds = calendar.component(.second, from: date)
return ("\(hour):\(minutes):\(seconds)")
}
}
struct ContentView: View {
var body: some View {
LogView()
}
}
struct LogView: View {
// Example text for new log events
let exampleLogMessage = "Log Message"
@AppStorage("logs") var logs: [LogItem] = []
func addLogItem(message: String) {
logs.append(LogItem(message: message))
}
var body: some View {
NavigationView() {
VStack(){
List() {
ForEach(self.logs, id: \.self){ item in
NavigationLink(destination: LogDetailedView(logItem: item)) {
HStack() {
Text("\(item.getDate())")
Spacer()
Text("\(item.getTime())")
}
}
}
}
// This button is just an example how to add items to the array, please see also the function that gets called addLogItem(message: String)
Button(action: {
self.addLogItem(message: exampleLogMessage)
}) {
Text("Log Event")
}
}
}
}
}
struct LogDetailedView: View {
var logItem: LogItem
var body: some View {
VStack() {
Text("Date: \(logItem.getDate())")
Text("Time: \(logItem.getTime())")
Text("Message: \(logItem.message)")
}
}
}
To use @AppStorage with a custom object Array must conform RawRepresentable, you achieve that with the following code/extension (just add it once somewhere in your project):
extension Array: RawRepresentable where Element: Codable {
public init?(rawValue: String) {
guard let data = rawValue.data(using: .utf8),
let result = try? JSONDecoder().decode([Element].self, from: data)
else {
return nil
}
self = result
}
public var rawValue: String {
guard let data = try? JSONEncoder().encode(self),
let result = String(data: data, encoding: .utf8)
else {
return "[]"
}
return result
}
}
And here are 2 screenshots (1. LogView - with the List of available logs; 2. LogDetailedView - with the log details (date, time and message):