"Type '()' cannot conform to 'View'" error Swift

845 Views Asked by At

I am receiving a

Type '()' cannot conform to 'View'"

error on the:

if let birthday = contact.birthday, let birthdayDate = Calendar.current.date(from: birthday) {

line. After looking in the error log I found:

Only concrete types such as structs, enums and classes can conform to protocols

and

Required by static method 'buildBlock' where 'C0' = '()'

Here is my BirthdayRow file, where I'm experiencing the

"Type '()' cannot conform to 'View'"

error.

//
//  BirthdayRow.swift
//  B-Day
//
//  Created by Joshua Wolfson on 29/7/2023.
//

import SwiftUI

struct GaugeProgressStyle: ProgressViewStyle {
    var strokeColor = Color.primary
    var strokeWidth = 7.0
    
    func makeBody(configuration: Configuration) -> some View {
        let fractionCompleted = configuration.fractionCompleted ?? 0
        
        return ZStack {
            
            Circle()
                .stroke(.tertiary, style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round))
            
            Circle()
                .trim(from: 0, to: fractionCompleted)
                .stroke(strokeColor, style: StrokeStyle(lineWidth: strokeWidth, lineCap: .round))
                .rotationEffect(.degrees(-90))
        }
    }
}


struct BirthdayRow: View {
    @State private var progress: Double
    
    let contact: Contact
    
    init(contact: Contact) {
        self.contact = contact
        
        self.progress = Self.calculateProgress(contact: contact)
    }
    
    static func calculateProgress(contact: Contact) -> Double {
        guard let birthday = contact.birthday, let birthdayDate = Calendar.current.date(from: birthday) else {
            return 0.0
        }
        
        let currentDate = Date()
        let calendar = Calendar.current
        
        let daysInYear: Double = 365.0
        let daysRemaining = Double(calendar.dateComponents([.day], from: currentDate, to: birthdayDate).day ?? 0)
        return (daysInYear - daysRemaining) / daysInYear * 100.0
    }
    
    var body: some View {
        VStack {
            HStack {
                VStack(alignment: .leading) {
                    Text("\(contact.firstName) \(contact.lastName)")
                        .font(.title3)
                        .fontWeight(.bold)
                    
                    HStack {
                        Text(contact.category)
                            .foregroundColor(Color.gray)
                        
                        Text("•")
                            .fontWeight(.black)
                        
                        if let birthday = contact.birthday, let birthdayDate = Calendar.current.date(from: birthday)
                        { //I'm receiving "Type '()' cannot conform to 'View'" error here
                            let dateFormatter = DateFormatter()
                            dateFormatter.dateFormat = "dd/MM/yyyy"
                            Text(dateFormatter.string(from: birthdayDate))
                                .foregroundColor(Color.gray)
                        } else {
                            Text("Unknown")
                                .foregroundColor(Color.red)
                        }
                    }
                }
                
                Spacer()
                
                ProgressView(value: progress, total: 100.0)
                    .progressViewStyle(GaugeProgressStyle())
                    .frame(width: 26, height: 26)
                    .contentShape(Rectangle())
            }
            .padding(.horizontal)
        }
    }
}

My ContentView is below:

//
//  ContentView.swift
//  B-Day
//
//  Created by Joshua Wolfson on 28/7/2023.
//

import Contacts
import SwiftUI

struct ContentView: View {
    @State private var selection = "All"
    @EnvironmentObject var modelData: ModelData
    var filteredContacts: [Contact] {
        modelData.contacts.filter { contact in
            (selection == "All" || contact.category == selection)
        }
    }
    var availableCategories: [String] {
        var categories = ["All"]
        categories.append(contentsOf: Set(modelData.contacts.map { $0.category }).sorted())
        return categories
    }
    var body: some View {
        
        NavigationStack{
            List {
                ForEach(filteredContacts) {contact in
                    NavigationLink {
                        BirthdayDetail(contact: contact)
                    } label: {
                        BirthdayRow(contact: contact)
                    }
                }
            }
            
            
            .navigationTitle(selection == "All" ? "Birthdays" : selection)
            
            .toolbar {
                
                ToolbarItem (placement: .navigationBarLeading){
                    Menu(content: {
                        Picker("Destination", selection: $selection) {
                            ForEach(availableCategories, id: \.self) {
                                Text($0)
                            }
                        }
                    },
                         label: { Label ("Filter", systemImage: "line.horizontal.3.decrease.circle") })
                }
                
                ToolbarItem (placement: .navigationBarTrailing) {
                    Button {
                        print("Sync Contacts")
                    } label: {
                        Image (systemName: "arrow.triangle.2.circlepath")
                    }
                }
                
                ToolbarItem (placement: .navigationBarTrailing) {
                    Button {
                        print("Add Birthday")
                    } label: {
                        Image(systemName: "plus")
                    }
                }
            }
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}
2

There are 2 best solutions below

0
Beom On

The location of the following code is incorrect.

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd/MM/yyyy"

The above code cannot be executed because it is inside var body: some View.

So, you should avoid processing the above code inside var body: some View.

0
Семен Медведев On

You should move birthday text preparation logics out of var body: some View

You can refactor it with separate method:

    func birthdayText(birthDayComponents: DateComponents?) -> Text {
        if let birthday = birthDayComponents,
           let birthdayDate = Calendar.current.date(from: birthday) {

            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "dd/MM/yyyy"
            return Text(dateFormatter.string(from: birthdayDate))
                .foregroundColor(Color.gray)
        } else {
            return Text("Unknown")
                .foregroundColor(Color.red)
        }
    }

Also replace same code in HStack with this:

birthdayText(birthDayString: contact.birthday)