Help with logic for updating UI based on sever response

Illustration link: h ttps://drive.google.com/file/d/1xwrbqYs87wtksupbXHFI_vDXZ_OHvvKC/view?usp=sharing


Over the last couple of days, I have been working on a progress tracker class / UI (see link above for illustration) that will be used to keep customers updated on the status of their order. One of the problems I am trying to solve is how to update the progress tracker based on a response from the server. So far I have mapped it out to the following ( my illustration above actually has this mapped out in more detail, please take a look, I think it will help explain it clearly)


Essentially I have:

1. An image library array that stores the images for the different stages for the progress tracker

2. An UIColor array that stores the colors that the image can be (for example, the "Build" image can be green meaning the product has been manufactured, or yellow meaning the product in in manufacturing.


3. The progress tracker will be updated based on a respone from ther sever, so if the server sends back [0,1], the approriate image from the image array and the corresponding color will be applied to it and then the progress tracker would update with the image and color.


Again, my lllustration maps it out more visually and it has a method I am working on... I would appreciate any advice on how to make this work or even if I'm on the right track. I'm thinking about using a dictionary, I also research into using the Set collection type, but I dont know if that's the right approach.


Thanks!

Answered by mkhan094 in 325167022

Figured out the dictionary parsing issue

Can you show where you listen / read server response ?


Then probably, just sending a notification that progress tracker will subscribe to should do the work.

Okay, so I am working on the Front End part and we don't have our backend working other than knowing that we are going to be using AWS. I ws basically gonna send in a sample response from a server. Bascially, have a JSON file and then get the response from there. We currently don't have our backend up and running... so is there a way to simulate this?

Of course, you can set up a server on the Mac… But that may be extra work.


The simplest is to replace the part where you analyze the JSON reply by some code that create the JSON result directly in code, and then continue executing.

Okay.. let me try that. Could you explain a little bit about what you were alluding when you mentioned sending a notification that the progress tracker will subscribe to?

The first thing I have to here is to take my imageLibrary and colorLibrary array and make a Dictionary of type [Int:Int]. My arrays are images and colors, so I wrote a small method that takes in the arrays and uses that to make an indices array for each which is then used to build the dictionary. The problem is that the output is not what i am expecting..


My expected dictionary output -> [0:0, 1:1, 2:2, 3:3]

My actual dictionary output -> [ 2:2, 0:0, 1:1, 3:3]


The other issue is I mapped one image to exclusively one color where in reality I need to match every image to every color:


0:0, 0:1, 0:2

1:0, 1:1, 1:2


Maybe a diffrent collection type of different approach altogther... here is my code so far with the incorrect dictionary oupput:


//: Playground - noun: a place where people can play

import UIKit


// Images
var starImage = UIImage(named: "star")
var buildImage = UIImage(named: "build")
var inspectImage = UIImage(named: "inspect")
var shipImage = UIImage(named: "ship")


// Make color image dictionary
func makeColorImageDictionary() -> Dictionary<Int,Int>  {
   
   // dictionary
   var colorImageDictionary: [Int:Int]
   
   
   // arrays for images and colors
   let imageLibrary = [starImage, buildImage, inspectImage, shipImage]
   let colorLibrary = [UIColor.gray, UIColor.yellow, UIColor.red, UIColor.green]
   
   
   // arrays for storing the indices for the arrays above
   var imageIndices = [Int]()
   var colorIndices = [Int]()
   
   
   // looping through imageLibrary array and getting index of each
   // image and then appending to imageIndices
   for image in imageLibrary {
      
      
      let imageIndex = imageLibrary.index(of: image)
      imageIndices.append(imageIndex!)
      
      
      
   }
   
   
   // looping through colorLibrary array and getting index of each
   // color and then appending to colorIndices
   for color in colorLibrary {
      
      
      let colorIndex = colorLibrary.index(of: color)
      colorIndices.append(colorIndex!)
      
      
      
   }
   
   
   // constructing colorImageDictionary
   colorImageDictionary = [imageIndices[0]:colorIndices[0], imageIndices[1]:colorIndices[1], imageIndices[2]:colorIndices[2], imageIndices[3]:colorIndices[3]]
   
   // return dictionary
   
   return colorImageDictionary

}


// function call in playgrounds to test
// this where the output is unordered
makeColorImageDictionary()

On the first point :


My expected dictionary output -> [0:0, 1:1, 2:2, 3:3]

My actual dictionary output -> [ 2:2, 0:0, 1:1, 3:3]


This is because the order of sequence in a dictionary is not guaranteed.


But I do not understand what you are doing by building those indices.


Why not either :

- create directly a dictionary with images and colors. Then the order is probably not a problem


   let imageLibrary = [starImage, buildImage, inspectImage, shipImage]
   let colorLibrary = [UIColor.gray, UIColor.yellow, UIColor.red, UIColor.green]
   var imagesColorDico: [UIImage : UIColor] = [:]
     for i in 0...3 {
          imagesColorDico[imageLibrary[i]] = colorLibrary[i]
     }


- You could also populate manually


   imagesColorDico = [starImage: UIColor.gra, buildImage: UIColor.yellow, inspectImage: UIColor.red, shipImage: UIColor.green]


- Or make t-uples, in fact pairs, with zip function, : this will remain in initial order


   let imageLibrary = [starImage, buildImage, inspectImage, shipImage]
   let colorLibrary = [UIColor.gray, UIColor.yellow, UIColor.red, UIColor.green]
   let imagesColorPairs = zip(imageLibrary, colorLibrary)


You can later use them like


for (image, color) in imagesColorPairs {  
     print(image, color)
}

Explain sending a notification that the progress tracker will subscribe to?


Create a notificationName

extension Notification.Name {
    public static let kUpdateTracker = Notification.Name("UpdateTracker")     // Useful to make sure the notification name is checked by compiler
}

- The progress tracker class would add an observer to kUpdateTracker (in its viewDidLoad method)


        NotificationCenter.default.addObserver(self, selector: #selector(refreshTracker), name: .kUpdateTracker, object: nil)

and a func to handle the update


    @objc func refreshTracker() { 
          // Update what needs to be updated
}


- when you have received and analyzed the JSON, post notification

        NotificationCenter.default.post(name: .kUpdateTracker, object: self)

My reasoning for the indices is as follows:


imageArray [image1, image2, image3, image4] ---> imageIndices [0,1,2,3]

colorArray [gray, yellow, red, green] ---> colorIndices [0,1,2,3]


The reason I am converting it to indices is the server will send a response like [2:2]. This means that image2 must be colored red. Based on the server response, a method would be called that would update the correct image with the correct color and update the progress tracker. That's the reason I have the indices because the serber doesnt know the images or colors.


My other solution was to have enums for my progress tracker for each state like so... In that case I could have the server send a response whenever the case status changes with a single int for example 0 would correspond to pending and so forth... in that case I would pass pending into the update tracker and it there would be logic to updatet he progress bar's icon colors. Is that a better solution?


enum States {


case pending

case building

case inspection

case shipped

case delivered

}

OK. But then, the fact that the dictionary is not ordered is no problem !


- Either server sends always the same value for bot indices (0:0 1:1 ……)

Then just use the first value for lookup in the 2 arrays of images and colors

imageArray[index]

colorArray[index]


- Or you have to read image and color indices and call

imageArray[firstIndex]

colorArray[secondIndex]

We kind of changed our approach and our sample (and simple for now) JSON file looks like this:


orderPlaced, orderBeingMade, and orderShipped are the image names... and done, pending, and empty are its states.

Basicially... this will tell us what color to give each image in the tracker... since orderPlaced is "done", its color will be green.


{

"orderPlaced": "done",
"orderBeingMade": "pending",
"orderShipped": "empty",


}


Before I even get to that I need to parse this JSON out.. I was successfully able to make an array, however, I need to make a dictionary where I can do something like



// image decalaration here

var responseDictionary [imageName:imageStatus] // String:String basically

for (image, status) in responseDictionary {
     
     // This follwing i know how to do :)
     // color the images according to the status
     // Store images in an array
     // This array is linked to the progress tracker and logic is already tehre to
     // populate the image views

}


Here is my current code and I dont know how to turn my implementation to output a dictionary:


// Struct for JSON
struct ServerResponse: Decodable {
      
      let orderPlaced: String
      let orderBeingMade: String
      let orderShipped: String  
      
   }

// for now its in view did load
override func viewDidLoad() {
      super.viewDidLoad()
      
      var responseArray = [String]()
      

      // Currently JSON is a local file in Xcode for testing purposes
      if let path = Bundle.main.path(forResource: "JSONPayload2", ofType: "json") {
         
         
         do {


            let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
            let response = try JSONDecoder().decode(ServerResponse.self, from: data)
            
        
            // Bad coding.. should append in a way where I dont have to
            // call append like this.. will fix later.
            responseArray.append(response.orderPlaced)
            responseArray.append(response.orderBeingMade)
            responseArray.append(response.orderShipped)
            
  
            
         } catch let jsonErr {
            
            print("err", jsonErr)
            
         }
      }



Any help on this would be appreciated! Thanks!!

Accepted Answer

Figured out the dictionary parsing issue

Help with logic for updating UI based on sever response
 
 
Q