How can I change the progress bar value when another tab is selected?

When I change tab on the tabBar my app can't change the progress bar on the first tab and the app crashes with a "found nil" error if I try to change it.

Answered by Claude31 in 710991022

If you split in 2,

 print("RAMBar", self.RAMBar)
 print("RAMBar.progress", self.RAMBar.progress)

I guess it crashes on the second print ?

Of course you could test for nil, but not sure it will give the result you expect:

                do {
                    let response = try JSONDecoder().decode(statsServerInfo.self, from: data)

                    DispatchQueue.main.async {
                        if self.RAMBar != nil {
                           if (self.tabBarController?.tabBar.selectedItem?.tag == 0) {
                                self.RAMBar.progress = Float(response.out)/100
                           }
                        }
                    }
                }

Could you show the code of the 2 viewControllers ?

And explain when and where exactly the crash occurs.

Most likely you try to access to the progress bar which is not or no more existing.

I've got only a ViewController.swift that handles all tabs, this is the erroring code:

func parseRAM(){

            guard let url = URL(string: "http://\(hostname):\(port)/STOInfo/Stats/RAM")else{

                return

            }

            var request = URLRequest(url: url)

            request.httpMethod = "POST"

            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

            let body: [String: AnyHashable] = [

                "username": username,

                "password": password,

            ]

            request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)

            let task = URLSession.shared.dataTask(with: request) {data, _, error in

                

                guard let data=data, error == nil else{

                    return

                }

                do{

                    let response = try JSONDecoder().decode(statsServerInfo.self, from: data)

                    print("SUCCESS: \(response)")

                    DispatchQueue.main.async{

                        if (self.tabBarController?.tabBar.selectedItem?.tag == 0){

                                self.RAMBar.progress = Float(response.out)/100

                        }

                    }

                    

                }

                catch{

                    print(error)

                }

            }

            task.resume()

        

        

    }

    @IBOutlet var CPUBar: UIProgressView!

    @IBOutlet var RAMBar: UIProgressView!

The UIProgressViews are on the first tab. The function automatically runs every 10 seconds with a timer. The error is thrown here: self.RAMBar.progress = Float(response.out)/100

The error happens only if I switch tabs, then I tried putting an if, to check the tab and now, with this code, it happens when, after I switch tabs, I return on the first tab. The exact output is:

SUCCESS: statsServerInfo(ok: true, out: 4)

ServiceTOOLS_Control/ViewController.swift:307: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

2022-04-14 14:52:59.783278+0200 ServiceTOOLS Control[4837:261227] ServiceTOOLS_Control/ViewController.swift:307: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

It's easier to read when you paste and Match Style…

@IBOutlet var CPUBar: UIProgressView!

@IBOutlet var RAMBar: UIProgressView!

func parseRAM() {
            guard let url = URL(string: "http://\(hostname):\(port)/STOInfo/Stats/RAM") else {
                return
            }

            var request = URLRequest(url: url)
            request.httpMethod = "POST"
            request.setValue("application/json", forHTTPHeaderField: "Content-Type")

            let body: [String: AnyHashable] = [
                "username": username,
                "password": password,
            ]

            request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: .fragmentsAllowed)

            let task = URLSession.shared.dataTask(with: request) {data, _, error in
                guard let data=data, error == nil else {
                    return
                }

                do {
                    let response = try JSONDecoder().decode(statsServerInfo.self, from: data)

                    print("SUCCESS: \(response)")
                    DispatchQueue.main.async {
                        if (self.tabBarController?.tabBar.selectedItem?.tag == 0) {
                                self.RAMBar.progress = Float(response.out)/100
                        }
                    }
                }

                catch {
                    print(error)
                }
            }

            task.resume()

    }

Who is nil ? self.RAMBar.progress ?

Where do you call parseRAM() ?

Nil comes from self.RAMBar.progress when it gives me the error. parseRAM is called by a timer.

Timers under viewDidLoad: (parseCPU the same function as parseRAM, with the URL changed)

    var CPUTimer = Timer()

    var RAMTimer = Timer()
        self.CPUTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true, block: { _ in self.parseCPU()

        })

        self.RAMTimer = Timer.scheduledTimer(withTimeInterval: 10, repeats: true, block: { _ in self.parseRAM()

        })

Video of the problem:

https://1drv.ms/v/s!AvW19IT_YDbihIspgUGKorL_MEURaA?e=erVeIH The class is ViewController:UIViewController

Returning to the original question:

When I change tab on the tabBar my app can't change the progress bar on the first tab and the app crashes with a "found nil" error if I try to change it.

Where in code do you try to change progress bar? Please understand it is really hard to get a grasp on your problem with partial views of code, if we cannot see how all fit together.

In addition, you did not show which line of code exactly the crash occurs.

Likely RAMBar is deallocated when you return and not reloaded.

Where is func parseRAM() located (in which class) ?

How is it you have to test for the tabBar.selectedItem?.tag ?

Could you show the whole code of ViewController ?

And add a few more logs:

                do {
                    let response = try JSONDecoder().decode(statsServerInfo.self, from: data)

                    print("SUCCESS: \(response)")
                    DispatchQueue.main.async {
                        print("RAMBar", self.RAMBar, "RAMBar.progress", self.RAMBar.progress)
                        if (self.tabBarController?.tabBar.selectedItem?.tag == 0) {
                                self.RAMBar.progress = Float(response.out)/100
                        }
                    }
                }

What do you get then ?

It would be better to post in reply, so that text is properly formatted.

parseRAM is under class ViewController: UIViewController.

The logs:

STO Backend is up.
SUCCESS: statsServerInfo(ok: true, out: 11) 
RAMBar Optional(<UIProgressView: 0x10320f0a0; frame = (16 192.5; 288 4); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x281ab4800>>) 
RAMBar.progress 0.0 
STO Backend is up. 
SUCCESS: statsServerInfo(ok: true, out: 11) 
RAMBar Optional(<UIProgressView: 0x10320f0a0; frame = (16 192.5; 288 4); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x281ab4800>>) 
RAMBar.progress 0.11 
SUCCESS: statsServerInfo(ok: true, out: 10) 
RAMBar Optional(<UIProgressView: 0x10320f0a0; frame = (16 192.5; 288 4); opaque = NO; autoresize = RM+BM; layer = <CALayer: 0x281ab4800>>) 
RAMBar.progress 0.11 

I change tab

SUCCESS: statsServerInfo(ok: true, out: 10) ServiceTOOLS_Control/ViewController.swift:302: 
Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value 2022-04-18 18:26:45.461472+0200 ServiceTOOLS Control[2730:247910] ServiceTOOLS_Control/ViewController.swift:302: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value 

Originally the problem happened when I changed tabs, now it happens when after I change tab I return to the first tab.

When you say "I change tab", do you mean "return to first tab" ?

The error now happens on the print line that you added and right when I change tab.

Do you mean here ?

                    print("SUCCESS: \(response)")

or here

                        print("RAMBar", self.RAMBar, "RAMBar.progress", self.RAMBar.progress)

In the latter, you should get a log with SUCCESS after returning to tab.

Please be very precise in your information, otherwise it is very hard to guess.

Yes, I meant return to the first tab. The error comes from 

print("RAMBar", self.RAMBar, "RAMBar.progress", self.RAMBar.progress)
Accepted Answer

If you split in 2,

 print("RAMBar", self.RAMBar)
 print("RAMBar.progress", self.RAMBar.progress)

I guess it crashes on the second print ?

Of course you could test for nil, but not sure it will give the result you expect:

                do {
                    let response = try JSONDecoder().decode(statsServerInfo.self, from: data)

                    DispatchQueue.main.async {
                        if self.RAMBar != nil {
                           if (self.tabBarController?.tabBar.selectedItem?.tag == 0) {
                                self.RAMBar.progress = Float(response.out)/100
                           }
                        }
                    }
                }

Actually, it crashes on the first print:


RAMBar nil

ServiceTOOLS_Control/ViewController.swift:303: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

2022-04-19 17:14:55.083701+0200 ServiceTOOLS Control[356:5920] ServiceTOOLS_Control/ViewController.swift:303: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value

Testing for nil doesn't update the RAMBar but I accept it as a result because I don't mind if it updates while on another tab, the important thing is that the program doesn't crash.

How can I change the progress bar value when another tab is selected?
 
 
Q