Xcode crash Allow Automatic Refresh

Hi All,

I am experiencing an Xcode crash whilst running my Xcode project, and also having problems customising my NavigationController as I am unable to use init() in my view due to the view in question not allowing my vars to be passed to it.

I have added code comments.

I will link my entire project as a zip.

Project

Alan,

Can you post a screen shot of the crash you are getting?

I just ran your code and no crash occurred. I get a list of names like this:

and if I tap on a row I get an avatar like this:

Hi Chris,

Yep as soon as I enabled the Auto Refresh, Wham!

I am now back on Internal SSD for the moment, although my external SSD via USB 3.0 is faster
(point for observation)

I have a 2018 MacBook Pro with:
6 cores running @ 2.2Ghz
16GB RAM - Reasonably insane
256GB SSD - Cause to run cheap 1TB SSD on a USB 3 caddie

No way is my machine unable to cope.

I thought maybe that my code was somewhat failing, but now I am thinking it might be a version thing?

Regards

Alan

Change your dummy data so that the id values start at 0 since it’s an array.

        let toSendToServer = [
            arrDataToSend(id: 0, firstName: "Alan", surName: "Trundle", avatar: "https://myswift.co.uk/familyapp/bartSimpson_135x135.png"),
            arrDataToSend(id: 1, firstName: "Malcolm", surName: "Trundle", avatar: "https://myswift.co.uk/familyapp/homerSimpson_135x135.png"),
            arrDataToSend(id: 2, firstName: "Gilly", surName: "Trundle", avatar: "https://myswift.co.uk/familyapp/margeSimpson_135x135.png"),
            arrDataToSend(id: 3, firstName: "Angie", surName: "Trundle", avatar: "https://myswift.co.uk/familyapp/maggieSimpson_135x135.png")
        ]

Now you can remove the if let statement from the AvatarScreen View and use index in place of myArrItem

struct AvatarScreen: View {
    
    
    let navBarAppearance = UINavigationBar.appearance()

    @Environment(\.presentationMode) var presentation
    @ObservedObject var dataViewModel: webServices = webServices()
    
    // Can't use init as it upsets my Index Int below
    // How else can I set my Navigation style on this View only ?
    
    //init() {
    //    navigationController?.navigationBar.titleTextAttributes = [ NSAttributedString.Key.foregroundColor : UIColor.white ]
    //}
    
    var index: Int
    
    var body: some View {

//        if let myArrItem = dataViewModel.myTestArrayRX.firstIndex(where: {$0.id == index}) {
            ZStack {
                Color.pink
                    .ignoresSafeArea()
                
                VStack {
                    HStack {
                        Text(dataViewModel.myTestArrayRX[index].firstName + "'s Avatar")
                            .font(.title2)
                            .foregroundColor(.white)
                            .padding([.top, .leading, .bottom])
                        
                        Spacer()
                    }
                    
                    AsyncImage(url: URL(string:dataViewModel.myTestArrayRX[index].avatar)) { image in
                        image
                            .resizable()
                            .aspectRatio(contentMode: .fill)
                            .frame(width:200, height:200)
                    } placeholder: {
                        ProgressView()
                    }
                    
                    
                    Spacer()

                }
                .navigationTitle("My Avatar")
                .foregroundColor(.white)
                .navigationBarBackButtonHidden(true)
                .navigationBarItems(leading: Button(action : {
                    self.presentation.wrappedValue.dismiss()
                }){
                    Image(systemName: "arrow.left")
                        .foregroundColor(Color.white)
                })
            }
//        }
    }
}

Previews are very tricky to get working.

Hi Chris,

Nope I am unable to do this since my myArrItem needs to allocated with what’s being sent.

I have set up my Mac from scratch, and have updated its fully.
Bamboozled

Xcode Version 13.2.1 (13C100)
macOS Monterey

Commented and removed the “if” is semention faulted

Regards

Alan

OK here is your project updated so that the Preview now works.

The ObservableObject is injected into the View hierarchy at the top level (Array_ExampleApp) as an EnvironmentObject and each View has that injected as an @EnvironmentObject rather than an @ObservedObject.

The onAppear is not required since the send and receive is done in the ObservableObject via the init() function as you had previously.

Let me know what you reckon.

One other point is that your ObservableObject name should be capitalised. Rather than webServices, it should be WebServices.

The convention is that class, struct, protocol, enums etc should be capitalised but your variables (properties) should start with a lowercase letter.

Hi Chris,

It runs good, thanks very much.
I will revise what I did wrong tomorrow.

Is there any chance we could customise my NavigationTitle?
In particular how I can set the foregroundColor.

I am starting work on a portfolio app for a job as a junior developer.

In particular I am going to write a Chinese takeaway app, with a shopping basket, icons of cuisines, and a checkout process (minus card payment), but will write an Android app to print a “ticket” takeaway side to print the Customer’s choices.
Sunmi V2

No orders yet!!

Many Thanks

Alan

No worries Alan.

Dunno about NavigationTitle customisation. Do you mean changing the foreground of the large title as in “Family Members” in this screenshot?

Hi Chris,

I want White text on my avatar view “My Avatar”.

init() won’t work, since it messes with my index: Int

Uncomment my init() in avatar view.

Regards

Alan

OK let me take a look at that.

Where are you located? UK?

Hi Chris,

I am in Reading, RG5 postcode UK

I am out of work at the moment. Been given a lucky break to learn SwiftUI, since I am out of work, and recieving a basic, but fair government allowance.
My wish is to update them with progress on my back to work program as a junior developer !

God save Alan

Alan

1 Like

You can change the text Color but it has to be done in an init() at the ContentView level where the NavigationView is specified. The problem there is that it affects the ContentView title color so that it is white on white. If you change your simulator to Dark mode then it’s fine but that’s probably not the best solution.

Updated project:

Hi Chris,

that’s fair, and thank you for your time.
I have spent hours googling, and it always come down to the init() on that View, which destroys my index var.

I want to specify it right where I set it, non global sense.

I did a ton of googling, and no fix yet.

Thank you for your help.

I am learning

Learning

Regards

Al.

In that AvatarView the init needs to include the index like this:

    init(index: Int) {
        self.index = index
        UINavigationBar.appearance().titleTextAttributes = [.foregroundColor: UIColor.white]
    }

Then you are good to go. The problem is that the UINavigationBar… code has no effect at the child level.

Hi Chris,

I spent at least 4 hours today on Google, and saw lots of examples, but like you said you can’t change the NavigationView appearance from other views (child views), or at least I can’t see how to do it.
In Objective C I think you could force redrawing.

So, I am still unable to change the Text foregroundColor, but I did manage from the child view to change the backgroundColor by adding a modifier.

so I went on successfully modifying a class I found to place a “Text” in the middle of the NavigationBar.
Over the top in ZStack.

Sort of works

struct AvatarScreen: View {
   let index: Int
   @ObservedObject var dataViewModel: webServices = webServices()
   @Environment(\.presentationMode) var presentation
   
   let statusBarModifier = NavigationBarModifier(backgroundColor: .blue, navTitle: "My Avatar")
  //   let statusBarModifier = NavigationBarModifier(backgroundColor: .blue, navTitle: "WS Example")
   
   init(index: Int, dataViewModel: webServices) {
       self.index = index
   }
   
   var body: some View {
       if dataViewModel.myTestArrayRX.firstIndex(where: {$0.id == index}) != nil {
           ZStack {
               Color.pink
                   .ignoresSafeArea()

               VStack {
                   HStack {
                       Text(dataViewModel.myTestArrayRX[index].firstName + "'s Avatar")
                           .font(.title2)
                           .foregroundColor(.white)
                           .padding([.top, .leading, .bottom])
                       
                       Spacer()
                   }
                   
                   AsyncImage(url: URL(string:dataViewModel.myTestArrayRX[index].avatar)) { image in
                       image
                           .resizable()
                           .aspectRatio(contentMode: .fill)
                           .frame(width:200, height:200)
                   } placeholder: {
                       ProgressView()
                   }
                   
                   
                   Spacer()

               }
               
               //.navigationTitle("My Avatar")
               .modifier(statusBarModifier)
               .navigationBarBackButtonHidden(true)
               .navigationBarItems(leading: Button(action : {
                   self.presentation.wrappedValue.dismiss()
               }){
                   Image(systemName: "arrow.left")
                       .foregroundColor(Color.white)
               })
           }
       }
   }
}

Here is the class/struct for it :

struct NavigationBarModifier: ViewModifier {
           
    var backgroundColor: UIColor?
    var navTitle: String
    
    init( backgroundColor: UIColor?, navTitle: String) {
        self.backgroundColor = backgroundColor
        self.navTitle = navTitle
  
      // Only works on the root view
        let coloredAppearance = UINavigationBarAppearance()
        coloredAppearance.configureWithTransparentBackground()
        coloredAppearance.backgroundColor = .clear
        coloredAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        coloredAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        
        UINavigationBar.appearance().standardAppearance = coloredAppearance
        UINavigationBar.appearance().compactAppearance = coloredAppearance
        UINavigationBar.appearance().scrollEdgeAppearance = coloredAppearance
        UINavigationBar.appearance().tintColor = .white

    }
    
    func body(content: Content) -> some View {
        ZStack{
            //content
            VStack {
                GeometryReader { geometry in
                    Color(self.backgroundColor ?? .clear)
                        .frame(height: geometry.safeAreaInsets.top)
                        .edgesIgnoringSafeArea(.top)
                    Spacer()
                }
            }
            // Added this to botch NavigationTitle
            VStack {
                Text(self.navTitle)
                    .font(.system(size: 20))
                    .fontWeight(.semibold)
                    .foregroundColor(.white)
                        .padding(20)
                        .ignoresSafeArea()
                        .multilineTextAlignment(.center)
            
                Spacer()
            }
            
            // now add the content back
            content
        }
    }
}


In the end, I decided to create a style for my Navigation Bar in the view that I created it, and that’s what I am using at the moment.

Doesn’t look like you can change it in the pushed view, but I have seen code that can change It realtime using color control as part of the App.

    init()
    {
        let navBarAppearance = UINavigationBarAppearance()
        navBarAppearance.largeTitleTextAttributes = [.foregroundColor: UIColor.white]
        navBarAppearance.titleTextAttributes = [.foregroundColor: UIColor.white]
        navBarAppearance.backgroundColor = .blue
        
        UINavigationBar.appearance().standardAppearance = navBarAppearance
        UINavigationBar.appearance().compactAppearance = navBarAppearance
        UINavigationBar.appearance().scrollEdgeAppearance = navBarAppearance
        UINavigationBar.appearance().tintColor = UIColor.systemBackground
        
    }

Regards

Alan

1 Like