UPGRADE YOUR SKILLS: Learn advanced Swift and SwiftUI on Hacking with Swift+! >>

I keep getting this error: "Thread 1: "-[AccountBackEnd accountCompanyName]: unrecognized selector sent to instance 0x6000025aac40""

Forums > SwiftUI

Hi Everyone,

I'm coming to you hat-in-hand again, as I'm really struggling with a point of my app that keeps crashing when I go to click on a cell in my list. Namely I get this error: Thread 1: "-[AccountBackEnd accountCompanyName]: unrecognized selector sent to instance 0x6000025aac40.". This appears right on the line of @main in the file that renders the app's output. To make matters worse, this is in SwiftUI and there doesn't seem to be a lot of documentation on this error online.

I'm not 100% sure, but I think it's got something to do with a syste for navigation that I downloaded, I was using which was meant to make navigation simpler. I don't think that's the case here. I've begun the process of going away from that system of buttons to use the more conventional NavigationView and NavigationLink.

I've managed to deal with a few errors already here, but this one seems to be kicking my butt pretty badly. I'm at a loss. I'll put my code below for your review.

As always, any help here is greatly, greatly appreciated.

Database view, this contains the app's list

struct DatabaseViewMain: View {

    //Fetch request for pulling from persistent store.
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \AccountBackEnd.accountCompanyName, ascending: true)],
        animation: .default)
    private var accounts: FetchedResults<AccountBackEnd>

    //Calls to Class for published objects
    @EnvironmentObject var publishedClasses: PublishedClasses

    //Takes object from @StateObject, presents as var
    @ObservedObject var accountBackEnd: AccountBackEnd = AccountBackEnd()

    var body: some View {

        VStack {
            HStack {
                Spacer()

                NavigationLink {
                    AddAccountView()
                } label: {
                    SubHeaderViewIcon(subheaderIcon: "plus.square", subheaderIconColor: Color("EditButtonBlue"))
                }
                .padding()

            }

            List {
                ForEach(accounts, id: \.self) {account in

                    NavigationLink {
                        AccountDetailMain(accountBackEnd: accountBackEnd)
                    } label: {
                        Text(account.accountCompanyName ?? "")
                    }
                }
                .onDelete(perform: deleteAccounts)
                .environmentObject(publishedClasses)
            }
            .listStyle(PlainListStyle())
        }
        .navigationBarHidden(true)
        .environmentObject(publishedClasses)
    }

    //Deleting Account
    private func deleteAccounts(offsets: IndexSet) {
        withAnimation {
            offsets.map { accounts[$0] }.forEach(viewContext.delete)
            do {
                try viewContext.save()
            } catch {
                print("Shit. Something happened. Error \(error.localizedDescription)")
                let nsError = error as NSError
                fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
            }
        }
    }
}

AccountDetailMain, this presents the user with their Account's info. I believe this is the part that is actually crashing the app?

struct AccountDetailMain: View {

    //Managed Object Context Call
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \AccountBackEnd.accountID, ascending: true)],
        animation: .default)
    private var accounts: FetchedResults<AccountBackEnd>

    //Calls from @Published
    @EnvironmentObject var publishedClasses: PublishedClasses

    //Takes object from @StateObject, presents as var
    @ObservedObject var accountBackEnd: AccountBackEnd

    var body: some View {

        ScrollView {

            VStack {
                MainHeaderViewTop(mainTextField: accountBackEnd.accountCompanyName ?? "", iconField: "building")
            }
            .environmentObject(publishedClasses)

            Spacer()
                .frame(height: 5)

            HStack {

                NavigationLink {
                    EditAccountView()
                } label: {
                    MainHeaderViewBottomLeft()
                }

                Spacer()

                NavigationLink {
                    AddAccountView()
                } label: {
                    SubHeaderViewIcon(subheaderIcon: "plus.square", subheaderIconColor: Color("EditButtonBlue"))
                }

            }

            ViewSpacer()

            Group {
                SalesRecords()
                ViewSpacer()

                LatestThreeQuotes()
                ViewSpacer()

                LatestNote()
                ViewSpacer()
            }

            Group {
                AccountsContactsView()
                ViewSpacer()

                BranchContactInfoView()
                ViewSpacer()

                AccountAddressView()
                ViewSpacer()

                RepDetailsView()
                ViewSpacer()
            }

            Group {

                NavigationLink {
                    EditAccountView()
                } label: {
                    LargeEditButtonGreen(editButtonLabel: "Edit Account")
                }

                ViewSpacer()

            }
            .environmentObject(publishedClasses)
        }
        .navigationBarHidden(true)
        .environmentObject(publishedClasses)
    }

}

AddAccountView, I can get this to load without challenge, where again it seems to be the AccountViewMain view that has issues.

struct AddAccountView: View {

    //Handles the in-out with the CoreData persistence store
    @Environment(\.managedObjectContext) private var viewContext
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \AccountBackEnd.accountID, ascending: true)],
        animation: .default)
    private var accounts: FetchedResults<AccountBackEnd>

    //Used for button/nav call out
    @Environment(\.presentationMode) var presentationMode

    //+++ From Paul Hudson, HWS
    @EnvironmentObject var publishedClasses: PublishedClasses

    var body: some View {

        ScrollView {

            VStack {
                Group {
                    MainAddHeaderView(mainTextField: "Account", iconField: "building")
                }

                Group{
                    AddAccountCompanyName()
                    ViewSpacer()

                    AddAccountAddress()
                    ViewSpacer()

                    AddAccountDetails()
                    ViewSpacer()

                    Button(action: addAccount) {
                        LargeSaveButtonBlue(saveButtonLabel: "Save Changes")
                    }                }

                ViewSpacer()

                LargeDeleteButton(deleteButtonLabel: "Cancel Changes")
                ViewSpacer()

            }
            .environmentObject(publishedClasses)

        }
        .navigationBarHidden(true)

    }

    //+++ Function for adding objects
    private func addAccount() {
        withAnimation {
            //Adds to persistence store
            let newAccount = AccountBackEnd(context: viewContext)
            newAccount.accountCompanyName = publishedClasses.accountNameForCoreData
            PersistenceController.shared.save
            {
                error in
                if let error = error {
                    print(error.localizedDescription)
                    return
                }
                print("Successfully saved account.")
            }

            //Exits  view
            self.presentationMode.wrappedValue.dismiss()
        }
    }
}

...As well, here's the last page with @main that has the issue on it:

import SwiftUI

@main
struct RangerCRM_SwiftUIApp: App {

    let persistenceController = PersistenceController.shared
    let publishedClasses = PublishedClasses()
    var account: AccountBackEnd = AccountBackEnd()

    var body: some Scene {

        WindowGroup {

            StatsAndDataTabView()
                .environment(\.managedObjectContext, persistenceController.container.viewContext)
                .environmentObject(publishedClasses)

        }
    }
}

3      

I don't see a definition of your AccountBackEnd class. But I was first struck by the question "Why are you identifying your objects in a ForEach loop with .self?

// Why use .self to identify your objects? Perhaps these should be unique. 
// Make them conform to Identifiable.
ForEach(accounts, id: \.self) {account in
                    NavigationLink {
                        AccountDetailMain(accountBackEnd: accountBackEnd)
                    } label: {
                        Text(account.accountCompanyName ?? "")
                    }
                }

You want unique items in your List, so when you send them to a new view, SwiftUI knows exactly what row is being rendered, updated, or deleted.

Another thought: You're looping through a found set names accounts. Your loop variable is named account. You use account.accountCompanyName as the filler for your navigation link's label. Yet, you're passing an accountBackEnd over to your AccountDetailMain() view. Since you are tapping a single account row, isn't this what you want to pass to your detail view?

Another thought: You've provided lots o' code! Much of this isn't pertinent to the problem. Have you tried commenting out big chunks of code to focus your attention on the source of the issue?

I'm not ready to do a deep dive into this code, but some of the code looks like red herring stuff. Is it a problem? Or just a decoy? For example, in your last code snip, I am not sure why you defined the account var ? This var is local to RangerCRM. But I do not see it used in a view, nor do I see it being passed to your StatsAndDataTabView.

Is this an issue? part of the problem? and oversight? It's a distraction.

struct RangerCRM_SwiftUIApp: App {
    let persistenceController = PersistenceController.shared
    let publishedClasses = PublishedClasses()
    var account: AccountBackEnd = AccountBackEnd()  //  WHAT'S THIS DOING HERE?

3      

Hi @Obelix,

Thanks you for taking the time to respond. As I'm sure you can tell, I'm learning while building. Thankfully I'm not building a house.

I'll try to answer your questions in sequence and see if that helps to clarify things.

1) My AccountBackEnd class is from Core data. So the actual class looks pretty empty. I'm honestly too green to tell if that's normal or not?

 import Foundation
import CoreData

@objc(AccountBackEnd)
public class AccountBackEnd: NSManagedObject {

}

2) Re my naming conventions, I thought it made more sense to keep my properties with lower case and the structs/classes with upper case. Admittedly I'm unsure how else to call the data from the list cell to the AccountViewMain in a way that makes sense.

3) Greying out code: This is one thing I've been doing, and has actually helped to really clean up parts of my code I don't need. I will continue to work on this.

4) Really good point. I greyed that one out, and have since removed it.

For what it's worth, I really do appreciate your time here. There's no one in my life that can go over this stuff with me so it really does help. Thank you!

3      

Does your AccountBackEnd actually have a property accountCompanyName?

Also:

    //Takes object from @StateObject, presents as var
    @ObservedObject var accountBackEnd: AccountBackEnd = AccountBackEnd()

I don't quite understand this line. If an AccountBackEnd object is being initialized in DatabaseViewMain, then it should be @StateObject rather than @ObservableObject. If it's being initialized elsewhere and passed in from a parent View to DatabaseViewMain, then it should be @ObservableObject but you shouldn't be initializing it. If it's passed down through the environment—which it seems like you intended to do since you create an AccountBackEnd in your RangerCRM_SwiftUIApp—then you need to add it as an .environmentObject at some point and read it out in DatabaseViewMain as @EnvironmentObject (like you do with PublishedClasses).

3      

Hi @roosterboy!

Thanks for your reply!

I just checked the AccountBackEnd, and there is a property there for accountCompanyName. This is found in its extension though. There is nothing in the class. I'll put the call below below.

@NSManaged public var accountCompanyName: String?

As for your second part, I thnk this is where I'm getting the most confused.

From what I know, the way to initialize something is like, init() {}. Is that correct? Is there a different way to initialize a class though? Initializing is something I'm still trying to get my head around beforte I go too further here.

Thanks!

EDIT To be clear there's wayyy more going on in an init() call, but I was trying to give the rough idea. Cheers!

3      

A little trick to find out which line of code is causing the exception:

  1. Open the breakpoint navigator (tag icon in top left).
  2. Create an exception breakpoint (plus in the bottom left). Leave all the defaults and click out of the pop-up.
  3. Run your app in the simulator and recreate the issue.

Xcode shows you the line of code that's causing the issue.

3      

You have this in several of your FetchRequests:

NSSortDescriptor(keyPath: \AccountBackEnd.accountID, ascending: true)

What type is accountID?

3      

BUILD THE ULTIMATE PORTFOLIO APP Most Swift tutorials help you solve one specific problem, but in my Ultimate Portfolio App series I show you how to get all the best practices into a single app: architecture, testing, performance, accessibility, localization, project organization, and so much more, all while building a SwiftUI app that works on iOS, macOS and watchOS.

Get it on Hacking with Swift+

Sponsor Hacking with Swift and reach the world's largest Swift community!

Archived topic

This topic has been closed due to inactivity, so you can't reply. Please create a new topic if you need to.

All interactions here are governed by our code of conduct.

 
Unknown user

You are not logged in

Log in or create account
 

Link copied to your pasteboard.