简体   繁体   中英

Trouble sorting array of custom object with UIImage and string data

I can not sort my array of custom objects. I have tried different swiftUI sorting methods but it doesn´t work and I suspect it has something to do with the struct model I have in my array. I save images in Firebase storage and saves their url:s together with some other data in an array of ImageModel, (my imageRefCollection in StudentModel). Then I fetch the images and stores them together with the other data (time and taskNr) in an array of ImageCollectionModel (my published var imageCollection). That is the array I want to sort.

This is my models: `


class StudentModel: Codable {

@DocumentID var id : String?
var name = ""
var district = ""
var school = ""
var courses = [Course]()
var activeCourse = Course()
var imageRefCollection = [ImageModel]()

}


struct ImageModel: Codable {

var time: String
var url: String
var taskNr: String

}



struct ImageCollectionModel {
    
    var image:UIImage
    var taskNr:String
    var time:String
}

`

And here is my variable in my contentModel:

@Published var imageCollection = [ImageCollectionModel]()

And here is my function that I call onAppear of my View where I show all the images. I want to show them sorted by time (which is a string, that I can sort when I just try that in testing) but when I try to sort my ImageCollection-array, it doesnt work.

`

func getAllImages() {
        
        let storageRef = Storage.storage().reference()
        self.imageCollection = [ImageCollectionModel]()
        
        if !student.imageRefCollection.isEmpty {
            
            for image in student.imageRefCollection {
                let fileRef = storageRef.child(image.url)
                
                fileRef.getData(maxSize: 5*128*128) { imageData, error in
                    if error == nil && imageData != nil {
                        
                        let fetchedImage = UIImage(data: imageData!) ?? UIImage()
                        let taskNr = image.taskNr
                        let time = image.time
                        let imageToAdd = ImageCollectionModel(image: fetchedImage, taskNr: taskNr, time: time)
                        self.imageCollection.append(imageToAdd)
                    }
                }
            }
            imageCollection.sort {
                $0.time < $1.time
            }
        }
    }
}

`

When I fetch the images, using the for-loop, the for loop first loops all the times and then after that it fetches the images but then in some "random" order (I guess that has something to do with the asyncronus thing that I never has really understood). But, nevertheless, it doesnt matter if I only could sort the array after all the images has been fetched. I have tried.sort, .sort(by: but I havent got it to work.

This is how my view looks with my.sort attempt (the grid displays in rows from left to right): with.sort {$0.time < $1.time}

And this is how it looks with attempt imageCollection = imageCollection.sorted {$0.time < $1.time} imageCollection = imageCollection.sorted {$0.time < $1.time}

Edit: Now I have tried to add DispatchGroup but I cant get it to work. My new code is:

`

func getAllImages() {
        
        let storageRef = Storage.storage().reference()
        
        if !student.imageRefCollection.isEmpty {
            
            let group = DispatchGroup()
            
            
            for image in self.student.imageRefCollection {
                group.enter()
                let fileRef = storageRef.child(image.url)
                
                fileRef.getData(maxSize: 5*128*128) { imageData, error in
                    if error == nil && imageData != nil {
                        
                        let fetchedImage = UIImage(data: imageData!) ?? UIImage()
                        let taskNr = image.taskNr
                        let time = image.time
                        let imageToAdd = ImageCollectionModel(image: fetchedImage, taskNr: taskNr, time: time)
                        self.imageCollection.append(imageToAdd)
                    }
                }
                group.leave()
            }
            group.notify(queue: DispatchQueue.global()) {
                self.imageCollection.sort { $0.time < $1.time }
            }
        }
    }

`

but that gives the following sort... Sort after dispatchgroup try

What do I do wrong?

You're not storing the result of your sorting in the variable. Use it like this:

imageCollection = imageCollection.sort { $0.time < $1.time }

func getAllImages() {
        
  let storageRef = Storage.storage().reference()
        
  if !student.imageRefCollection.isEmpty {
            
    let group = DispatchGroup()
            
      for image in self.student.imageRefCollection {
        group.enter()
        let fileRef = storageRef.child(image.url)
        fileRef.getData(maxSize: 5*128*128) { imageData, error in
          if error == nil && imageData != nil {
            let fetchedImage = UIImage(data: imageData!) ?? UIImage()
            let taskNr = image.taskNr
            let time = image.time
            let imageToAdd = ImageCollectionModel(image: fetchedImage, taskNr: taskNr, time: time)
            self.imageCollection.append(imageToAdd)
          }
          group.leave()
        }
      }
      group.notify(queue: DispatchQueue.global()) {
        self.imageCollection.sort { $0.time < $1.time }
      }
    }
  }
}

You should move group.leave() one line up. It should be executed just after async method returns response and append image to collection.

You should also convert String time object to Date object. For now .sort is working on String not on Date , that's why it sorts your items in wrong order. Finally, check if you receive proper string dates from api.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM