Home > Net >  When I loop through an array in a list, I get "compiler is unable to type-check" error?
When I loop through an array in a list, I get "compiler is unable to type-check" error?

Time:08-25

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):

1. LogView - with the List of available logs

2. LogDetailedView - with the log details (date, time and message)

  • Related