Search code examples
arraysswiftsortingcustom-object

Swift appending to an array with custom objects and sorting them


I am making a collection view that shows somebody their 'feed' which includes their compliments, likes, replies, and sent. I have an object named Feed which is made of an array of compliments, an array of likes, and array of replies, and an array of sent. Every object within those smaller arrays has a date_created property.

I know how to fill a collection view based off of one array sorted by dates, but how can I load a collection view with every like, reply, compliment, and sent from four arrays based on their date sent?

Do I perhaps append every one of these objects to one array? If so, how can I then go through that array and sort everything in it?

struct Feed: Decodable {
    let likes: [Like]
    let replies: [Reply]
    let compliments: [Compliment]
    let sent: [Compliment]
}

struct Like: Decodable {
    let id: Int
    let user: QuickUser
    let created_at: String
}

struct Reply: Decodable {
    let parent: Compliment
    let content: String
    let created_at: String
}

struct Compliment: Decodable {
    let id: Int
    let content: String
    let sender: QuickUser

    let created_at: String

    let is_liked: Bool
    let recipient: QuickUser
    let is_public: Bool
}

func getFeed() {
    UserServices.getInboxFeed { feed in
        guard let feed = feed else {
            self.showOkayAlert(title: "Oops!", message: "We are having trouble loading your inbox.", completion: nil)
            return
        }
        self.feed = feed

        DispatchQueue.main.async {
            //load collection view here
        }
    }
}

A mockup of what the collection view will look like mockup


Solution

  • Well, to solve this i have made a dummy protocol that contains the shared properties they all share.

    in this case it was created_at and i assume this should be in date format.

    however the next step was to make an extension of Feed that contains a function

    that returns the latest object that confirm to the dummy protocol that i called, it LatestAction,

    it basically sort each array by date and return the first item.

    in our case the latest date,

    after that creates a [LatestAction] sort it again the same way and return the first item which is the LatestAction.

    Observe the code below.

    struct QuickUser: Codable {
    
    }
    
    struct Feed: Decodable {
        let likes: [Like]
        let replies: [Reply]
        let compliments: [Compliment]
        let sent: [Compliment]
    }
    extension Feed {
        func latestAction() -> LatestAction {
            let latestLike = self.likes.sorted(by: { $0.created_at.compare($1.created_at) == .orderedDescending }).first!
            let latestReply = self.replies.sorted(by: { $0.created_at.compare($1.created_at) == .orderedDescending }).first!
            let latestComp = self.compliments.sorted(by: { $0.created_at.compare($1.created_at) == .orderedDescending }).first!
            let latestActions: [LatestAction] = [latestReply, latestLike, latestComp].sorted(by: { $0.created_at.compare($1.created_at) == .orderedDescending })
            return latestActions.first!
        }
    
    }
    protocol LatestAction  {
        var created_at: Date { get }
    }
    
    struct Like: Decodable, LatestAction {
    
        let id: Int
        let user: QuickUser
        let created_at: Date
    }
    
    struct Reply: Decodable, LatestAction {
    
        let parent: Compliment
        let content: String
        let created_at: Date
    }
    
    struct Compliment: Decodable, LatestAction {
    
        let id: Int
        let content: String
        let sender: QuickUser
    
        let created_at: Date
    
        let is_liked: Bool
        let recipient: QuickUser
        let is_public: Bool
    }
    
    
    
    // Simply used like this
    var latest = feed.latestAction() 
    

    We are not done yet if you checked the latest type it would say LatestAction and only can access the one property in there which is created_at,

    now the for the last part we are going to TypeCast the Object.

    if let latest = feed.latestAction() as? Like {
        // used as Like
    } else if let latest = feed.latestAction() as? Compliment {
        // used as Compliment
    } else if let latest = feed.latestAction() as? Reply {
        // used as reply
    }