Search code examples
arraysswiftclasscontainsequality

How to check equality of object properties in an array of objects. Swift


I have a class called Movie, which as of now, only has a string property called movieTitle.

I have an array of Movie, and using the .contains method returns false even when an object with the same title is in the array. Interestingly enough, .contains works in a playground I made but not in an app setting.

Thanks for the help! I'm fairly new to the programing game so if you and ELI5 things, that would be great!

Here's a snippet of the code I have. What ends up happening, is it just keeps adding the same 10 entries onto the array.

do{
    let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String: AnyObject]
        if let movieSearch = json["Search"] as? [[String: AnyObject]] {
            for movie in movieSearch {
                if let title = movie["Title"] as? String {
                    let newMovie = Movie(movieTitle: title)!

                    if (!self.movieList.contains(newMovie)) {
                        self.movieList.append(newMovie)
                    }
                    self.tableView.reloadData()
                }
            }
        }
    }catch {
        print("Error with Json: \(error)")
    }

Movie Class

import UIKit

class Movie: NSObject, NSCoding {
    // MARK: Properties

    struct PropertyKey {
        static let movieTitleKey = "title"
    }

    // MARK: Archiving Paths

    static let DocumentsDirectory = FileManager().urls(for: .documentDirectory, in: .userDomainMask).first!
    static let ArchiveURL = DocumentsDirectory.appendingPathComponent("Movies")

    var movieTitle: String

    // MARK: Initialization

    init?(movieTitle: String) {
        // Initialize stored properties.
        self.movieTitle = movieTitle

        super.init()

        // Initialization should fail if there is no itemName
        if movieTitle.isEmpty {
            return nil
        }
    }

    // MARK: NSCoding

    func encode(with aCoder: NSCoder) {
        aCoder.encode(movieTitle, forKey: PropertyKey.movieTitleKey)
    }

    required convenience init?(coder aDecoder: NSCoder) {
        let title = aDecoder.decodeObject(forKey: PropertyKey.movieTitleKey) as! String

        //Must call designated initializer.
        self.init(movieTitle: title)

    }
}


// MARK: Equatable
func ==(lhs: Movie, rhs: Movie) -> Bool { // Implement Equatable
    return lhs.movieTitle == rhs.movieTitle
}

What works in playgrounds

class Movie: NSObject {
    var movieTitle: String

    init?(movieTitle: String) {
        // Initialize stored properties.
        self.movieTitle = movieTitle

        super.init()

        // Initialization should fail if there is no itemName
        if movieTitle.isEmpty {
            return nil
        }

    }
}

var movieList = [Movie]()

var movie1 = Movie(movieTitle: "Batman")
var movie2 = Movie(movieTitle: "Batman")
var movie3 = Movie(movieTitle: "Superman")

movieList.append(movie1!)
movieList.append(movie2!)

movieList.contains(movie1!) // Returns True
movieList.contains(movie3!) // Returns False

Solution

  • Just try this code it works perfectly.

    do{
        let json = try JSONSerialization.jsonObject(with: data!, options:.allowFragments) as! [String: AnyObject]
            if let movieSearch = json["Search"] as? [[String: AnyObject]] {
                for movie in movieSearch {
                    if let title = movie["Title"] as? String {
                        let newMovie = Movie(movieTitle: title)!
    
                        let movieTitles = (self.movieList as NSArray).value(forKeyPath: "movieTitle") as? [String]
                        if movieTitles == nil || movieTitles!.contains(title) == false {
                            self.movieList.append(newMovie)
                        }
                        self.tableView.reloadData()
                    }
                }
            }
        }catch {
            print("Error with Json: \(error)")
        }