如何检查 object 数组中 object 属性的相等性。 Swift

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

我有一个名为 Movie 的 class,截至目前,它只有一个名为 movieTitle 的字符串 属性。

我有一个 Movie 数组,使用 .contains 方法 returns false 即使数组中有一个 object 具有相同的标题。有趣的是,.contains 在我制作的游乐场中有效,但在应用程序设置中无效。

感谢您的帮助!我是编程游戏的新手,所以如果你和 ELI5 东西,那就太好了!

这是我的代码片段。最终会发生什么,它只是不断将相同的 10 个条目添加到数组中。

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)")
    }

电影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
}

在操场上有什么用

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

因为你的Movieclass(为什么是class?)继承自NSObject(为什么?),它继承了NSObjectEquatable 协议的一致性,以及 ==NSObject 实现。默认情况下,这会进行身份比较(比较引用),而不是值比较。

这是一个例子:

let movie1 = Movie(movieTitle: "Batman")
let movie2 = Movie(movieTitle: "Batman")

var movieList = [Movie1]

movieList.contains(movie1!) // True, because movie1 was added in
movieList.contains(movie2!) // False, movie2 was never added

由于 Movie 不会使用比较其值的实现(例如 movieTitle)覆盖 ==,因此它遵循默认实现,即比较参考资料。尽管 movie2 具有相同的 value,但它是一个具有自己(单独的)内存位置的不同对象。因此,身份比较失败,没有找到。

要解决此问题,如果 Movie 的所有字段都匹配,则将 == 设置为 return true。但是,您尝试做的事情可能比 implemented with structs 更好。

你应该试试这个方法。

var filtered = [Movie]()
filtered = movieList.filter({[=10=].movieTitle == "Superman"})
if filtered.count == 1 {
//so,"Superman" movie contained in array..
}

让我知道结果...谢谢。

尝试覆盖 NSObjectisEqual 方法,因为它已经符合 Equatable 协议。您可以在操场上测试下面的代码。希望对你有帮助。

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
        }

    }

    override func isEqual(_ object: Any?) -> Bool {
        guard let theMovie = (object as? Movie) else { return false }
        return movieTitle == theMovie.movieTitle
    }
}

var movieList = [Movie]()

func appendToList(newMovie: Movie) {
    if (!movieList.contains(newMovie)) {
        movieList.append(newMovie)
    }
}

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

appendToList(newMovie: movie1!)
movieList.count             // count is 1

appendToList(newMovie: movie2!)
movieList.count             // count is still 1 not incremented

movieList.contains(movie1!) // Returns true
movieList.contains(movie2!) // Returns true
movieList.contains(movie3!) // Returns false

只需尝试使用此代码即可完美运行。

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)")
    }