Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 如何使用Equatable比较基于不同属性的自定义对象?_Swift_Equatable - Fatal编程技术网

Swift 如何使用Equatable比较基于不同属性的自定义对象?

Swift 如何使用Equatable比较基于不同属性的自定义对象?,swift,equatable,Swift,Equatable,我正在使用Equalable协议,以便基于一个名为mediaUID的属性比较两个自定义对象 有没有办法在比较不同属性之间切换? 在func fetchnotificationsreleved中,有时我需要通过mediaUID或likeUID进行比较 var notificationsArray = [NotificationInformation]() class NotificationInformation { let type: String let mediaUID

我正在使用Equalable协议,以便基于一个名为
mediaUID
的属性比较两个自定义对象
有没有办法在比较不同属性之间切换?
func fetchnotificationsreleved
中,有时我需要通过
mediaUID
或likeUID进行比较

 var notificationsArray = [NotificationInformation]()

class NotificationInformation {

    let type: String
    let mediaUID: String?
    let commentUID: String?
    let likeUID:String?    
}


extension NotificationInformation {
    func fetchNotificationsRemoved(query: DatabaseQuery) {

    NotificationInformation.observeNewNotificationsChildRemoved(query: query) { [weak self] (newNotification: NotificationInformation?) in

            guard let strongSelf = self else {return}
            guard let notification = newNotification else {return}

        if notification.type == "like" {

            // How to compare based on likeUID using equatable?
            //compare based on likeUID
            //get the index of the item of type 'like' in notificationsArray and do something with it
            guard let index = strongSelf.notificationsArray.index(of: notification) else {return}

        }else if notification.type == "media" {
            // How to compare based on mediaUID using equatable?
            //compare based on mediaUID
            //get the index of the item of type 'media' in notificationsArray
            guard let index = strongSelf.notificationsArray.index(of: notification) else {return}
        } else if if notification.type == "commentUID" {
           ....
   }


            guard let index = strongSelf.notificationsArray.index(of: notification) else {return}

            strongSelf.notificationsArray.remove(at: index)

            let visibleIndexes = strongSelf.tableView.indexPathsForVisibleRows
            let indexPathOfRemovedNotification = IndexPath(row: index, section: 0)

            if let indexes = visibleIndexes,
                indexes.contains(indexPathOfRemovedNotification) {
                strongSelf.tableView.deleteRows(at: [indexPathOfRemovedNotification], with: .fade)
            }
        }
    }

}//end extension

//enables us to compare two objects of type NotificationInformation
extension NotificationInformation: Equatable { }

func ==(lhs: NotificationInformation ,rhs: NotificationInformation) -> Bool {
    guard let mediaUIDLeft = lhs.mediaUID else {return false}
    guard let mediaUIDRight = rhs.mediaUID else {return false}
    return mediaUIDLeft == mediaUIDRight
}

您可以使用
静态var
来建立要用于比较的字段:

class NotificationInformation: Equatable {
    enum CompareField {
        case type, mediaUID, commentUID, likeUID
    }

    static var compareField: CompareField = .mediaUID

    let type: String
    let mediaUID: String?
    let commentUID: String?
    let likeUID:String?

    init(type: String, mediaUID: String? = nil, commentUID: String? = nil, likeUID: String? = nil) {
        self.type = type
        self.mediaUID = mediaUID
        self.commentUID = commentUID
        self.likeUID = likeUID
    }

    static func ==(lhs: NotificationInformation, rhs: NotificationInformation) -> Bool {
        switch NotificationInformation.compareField {
        case .type:
            return lhs.type == rhs.type
        case .mediaUID:
            return lhs.mediaUID == rhs.mediaUID
        case .commentUID:
            return lhs.commentUID == rhs.commentUID
        case .likeUID:
            return lhs.likeUID == rhs.likeUID
        }
    }
}
示例:

let a = NotificationInformation(type: "foo", mediaUID: "123")
let b = NotificationInformation(type: "bar", mediaUID: "123")

NotificationInformation.compareField = .type
if a == b {
    print("same type")
}

NotificationInformation.compareField = .mediaUID
if a == b {
    print("same mediaUID")
}
输出:

let a = NotificationInformation(type: "foo", mediaUID: "123")
let b = NotificationInformation(type: "bar", mediaUID: "123")

NotificationInformation.compareField = .type
if a == b {
    print("same type")
}

NotificationInformation.compareField = .mediaUID
if a == b {
    print("same mediaUID")
}

使用
选项开始比较多个字段

     let a: NotificationInformation = NotificationInformation()
     let b: NotificationInformation = NotificationInformation()

     //Check by `mediaUID`
     if a == b{
        ....
     }

     //Check by `likeUID`
     a.checkByMediaUID = false

     if a == b{
        ....
     }
如果用
选项开始
替换
枚举
,则可以选择多个字段进行比较:

struct CompareFields: OptionSet {
    let rawValue: Int

    static let type       = CompareFields(rawValue: 1 << 0)
    static let mediaUID   = CompareFields(rawValue: 1 << 1)
    static let commentUID = CompareFields(rawValue: 1 << 2)
    static let likeUID    = CompareFields(rawValue: 1 << 3)
}

static var compareFields: CompareFields = .mediaUID

static func ==(lhs: NotificationInformation, rhs: NotificationInformation) -> Bool {
    var equal = true

    if NotificationInformation.compareFields.contains(.type) {
        equal = equal && (lhs.type == rhs.type)
    }
    if NotificationInformation.compareFields.contains(.mediaUID) {
        equal = equal && (lhs.mediaUID == rhs.mediaUID)
    }
    if NotificationInformation.compareFields.contains(.commentUID) {
        equal = equal && (lhs.commentUID == rhs.commentUID)
    }
    if NotificationInformation.compareFields.contains(.likeUID) {
        equal = equal && (lhs.likeUID == rhs.likeUID)
    }

    return equal
}
输出


多线程问题

let a = NotificationInformation(type: "foo", mediaUID: "123", commentUID: "111")
let b = NotificationInformation(type: "bar", mediaUID: "123", commentUID: "111")

NotificationInformation.compareFields = .mediaUID
if a == b {
    print("same mediaUID")
}

NotificationInformation.compareFields = [.mediaUID, .commentUID]
if a == b {
    print("same mediaUID and commentUID")
}
extension NotificationInformation {
    func fetchNotificationsRemoved(query: DatabaseQuery) {
        NotificationInformation.observeNewNotificationsChildRemoved(query: query) { [weak self] newNotification in
            guard let strongSelf = self else {return}
            guard let notification = newNotification else {return}
            guard let index = strongSelf.notificationsArray.index(of: notification) else {return}
            strongSelf.notificationsArray.remove(at: index)
            let visibleIndexes = strongSelf.tableView.indexPathsForVisibleRows
            let indexPathOfRemovedNotification = IndexPath(row: index, section: 0)
            if let indexes = visibleIndexes, indexes.contains(indexPathOfRemovedNotification) {
                strongSelf.tableView.deleteRows(at: [indexPathOfRemovedNotification], with: .fade)
            }
        }
    }
}
如果代码正在修改另一个线程中的
compareFields
值,则会出现问题。对于所有线程,equals的含义都会改变。一种可能的解决方案是只更改主线程中的
通知信息
并使用相等性

...
} else if notification.type == "media" {
    DispatchQueue.main.async {
        NotificationInformation.compareFields = .mediaUID

        guard let index = strongSelf.notificationsArray.index(of: notification) else {return}

        // use index
        ...
    }
}
...

您可以使用
静态var
来建立要用于比较的字段:

class NotificationInformation: Equatable {
    enum CompareField {
        case type, mediaUID, commentUID, likeUID
    }

    static var compareField: CompareField = .mediaUID

    let type: String
    let mediaUID: String?
    let commentUID: String?
    let likeUID:String?

    init(type: String, mediaUID: String? = nil, commentUID: String? = nil, likeUID: String? = nil) {
        self.type = type
        self.mediaUID = mediaUID
        self.commentUID = commentUID
        self.likeUID = likeUID
    }

    static func ==(lhs: NotificationInformation, rhs: NotificationInformation) -> Bool {
        switch NotificationInformation.compareField {
        case .type:
            return lhs.type == rhs.type
        case .mediaUID:
            return lhs.mediaUID == rhs.mediaUID
        case .commentUID:
            return lhs.commentUID == rhs.commentUID
        case .likeUID:
            return lhs.likeUID == rhs.likeUID
        }
    }
}
示例:

let a = NotificationInformation(type: "foo", mediaUID: "123")
let b = NotificationInformation(type: "bar", mediaUID: "123")

NotificationInformation.compareField = .type
if a == b {
    print("same type")
}

NotificationInformation.compareField = .mediaUID
if a == b {
    print("same mediaUID")
}
输出:

let a = NotificationInformation(type: "foo", mediaUID: "123")
let b = NotificationInformation(type: "bar", mediaUID: "123")

NotificationInformation.compareField = .type
if a == b {
    print("same type")
}

NotificationInformation.compareField = .mediaUID
if a == b {
    print("same mediaUID")
}

使用
选项开始比较多个字段

     let a: NotificationInformation = NotificationInformation()
     let b: NotificationInformation = NotificationInformation()

     //Check by `mediaUID`
     if a == b{
        ....
     }

     //Check by `likeUID`
     a.checkByMediaUID = false

     if a == b{
        ....
     }
如果用
选项开始
替换
枚举
,则可以选择多个字段进行比较:

struct CompareFields: OptionSet {
    let rawValue: Int

    static let type       = CompareFields(rawValue: 1 << 0)
    static let mediaUID   = CompareFields(rawValue: 1 << 1)
    static let commentUID = CompareFields(rawValue: 1 << 2)
    static let likeUID    = CompareFields(rawValue: 1 << 3)
}

static var compareFields: CompareFields = .mediaUID

static func ==(lhs: NotificationInformation, rhs: NotificationInformation) -> Bool {
    var equal = true

    if NotificationInformation.compareFields.contains(.type) {
        equal = equal && (lhs.type == rhs.type)
    }
    if NotificationInformation.compareFields.contains(.mediaUID) {
        equal = equal && (lhs.mediaUID == rhs.mediaUID)
    }
    if NotificationInformation.compareFields.contains(.commentUID) {
        equal = equal && (lhs.commentUID == rhs.commentUID)
    }
    if NotificationInformation.compareFields.contains(.likeUID) {
        equal = equal && (lhs.likeUID == rhs.likeUID)
    }

    return equal
}
输出


多线程问题

let a = NotificationInformation(type: "foo", mediaUID: "123", commentUID: "111")
let b = NotificationInformation(type: "bar", mediaUID: "123", commentUID: "111")

NotificationInformation.compareFields = .mediaUID
if a == b {
    print("same mediaUID")
}

NotificationInformation.compareFields = [.mediaUID, .commentUID]
if a == b {
    print("same mediaUID and commentUID")
}
extension NotificationInformation {
    func fetchNotificationsRemoved(query: DatabaseQuery) {
        NotificationInformation.observeNewNotificationsChildRemoved(query: query) { [weak self] newNotification in
            guard let strongSelf = self else {return}
            guard let notification = newNotification else {return}
            guard let index = strongSelf.notificationsArray.index(of: notification) else {return}
            strongSelf.notificationsArray.remove(at: index)
            let visibleIndexes = strongSelf.tableView.indexPathsForVisibleRows
            let indexPathOfRemovedNotification = IndexPath(row: index, section: 0)
            if let indexes = visibleIndexes, indexes.contains(indexPathOfRemovedNotification) {
                strongSelf.tableView.deleteRows(at: [indexPathOfRemovedNotification], with: .fade)
            }
        }
    }
}
如果代码正在修改另一个线程中的
compareFields
值,则会出现问题。对于所有线程,equals的含义都会改变。一种可能的解决方案是只更改主线程中的
通知信息
并使用相等性

...
} else if notification.type == "media" {
    DispatchQueue.main.async {
        NotificationInformation.compareFields = .mediaUID

        guard let index = strongSelf.notificationsArray.index(of: notification) else {return}

        // use index
        ...
    }
}
...

将您的
func
更改为:

          func ==(lhs: NotificationInformation ,rhs: NotificationInformation) -> Bool {
            guard let mediaUIDLeft = lhs.mediaUID else {return false}
            guard let mediaUIDRight = rhs.mediaUID else {return false}

            return (mediaUIDLeft == mediaUIDRight || lhs.likeUID == rhs.likeUID)
         }
这意味着两个
通知信息
如果具有相同的
mediaUID
相同的
likeUID

如果需要条件检查,可以引入布尔变量:

    class NotificationInformation {

      let type: String
      let mediaUID: String?
      let commentUID: String?
      let likeUID:String?    

      let checkByMediaUID: Bool = true

    }
因此,请更改您的
均衡

      func ==(lhs: NotificationInformation ,rhs: NotificationInformation) -> Bool {
          guard let mediaUIDLeft = lhs.mediaUID else {return false}
          guard let mediaUIDRight = rhs.mediaUID else {return false}

          return (lhs.checkByMediaUID || rhs.checkByMediaUID) ? mediaUIDLeft == mediaUIDRight : lhs.likeUID == rhs.likeUID
      }
以更具可读性的方式:

   func ==(lhs: NotificationInformation ,rhs: NotificationInformation) -> Bool {
          guard let mediaUIDLeft = lhs.mediaUID else {return false}
          guard let mediaUIDRight = rhs.mediaUID else {return false}

          if lhs.checkByMediaUID || rhs.checkByMediaUID{
              return mediaUIDLeft == mediaUIDRight
          }

          return lhs.likeUID == rhs.likeUID
      }
这意味着,如果要通过
mediaUID
进行检查,只需比较两个对象即可。如果要通过likeUID进行检查,只需更改其中一个对象的变量即可

示例

let a = NotificationInformation(type: "foo", mediaUID: "123", commentUID: "111")
let b = NotificationInformation(type: "bar", mediaUID: "123", commentUID: "111")

NotificationInformation.compareFields = .mediaUID
if a == b {
    print("same mediaUID")
}

NotificationInformation.compareFields = [.mediaUID, .commentUID]
if a == b {
    print("same mediaUID and commentUID")
}
extension NotificationInformation {
    func fetchNotificationsRemoved(query: DatabaseQuery) {
        NotificationInformation.observeNewNotificationsChildRemoved(query: query) { [weak self] newNotification in
            guard let strongSelf = self else {return}
            guard let notification = newNotification else {return}
            guard let index = strongSelf.notificationsArray.index(of: notification) else {return}
            strongSelf.notificationsArray.remove(at: index)
            let visibleIndexes = strongSelf.tableView.indexPathsForVisibleRows
            let indexPathOfRemovedNotification = IndexPath(row: index, section: 0)
            if let indexes = visibleIndexes, indexes.contains(indexPathOfRemovedNotification) {
                strongSelf.tableView.deleteRows(at: [indexPathOfRemovedNotification], with: .fade)
            }
        }
    }
}

将您的
func
更改为:

          func ==(lhs: NotificationInformation ,rhs: NotificationInformation) -> Bool {
            guard let mediaUIDLeft = lhs.mediaUID else {return false}
            guard let mediaUIDRight = rhs.mediaUID else {return false}

            return (mediaUIDLeft == mediaUIDRight || lhs.likeUID == rhs.likeUID)
         }
这意味着两个
通知信息
如果具有相同的
mediaUID
相同的
likeUID

如果需要条件检查,可以引入布尔变量:

    class NotificationInformation {

      let type: String
      let mediaUID: String?
      let commentUID: String?
      let likeUID:String?    

      let checkByMediaUID: Bool = true

    }
因此,请更改您的
均衡

      func ==(lhs: NotificationInformation ,rhs: NotificationInformation) -> Bool {
          guard let mediaUIDLeft = lhs.mediaUID else {return false}
          guard let mediaUIDRight = rhs.mediaUID else {return false}

          return (lhs.checkByMediaUID || rhs.checkByMediaUID) ? mediaUIDLeft == mediaUIDRight : lhs.likeUID == rhs.likeUID
      }
以更具可读性的方式:

   func ==(lhs: NotificationInformation ,rhs: NotificationInformation) -> Bool {
          guard let mediaUIDLeft = lhs.mediaUID else {return false}
          guard let mediaUIDRight = rhs.mediaUID else {return false}

          if lhs.checkByMediaUID || rhs.checkByMediaUID{
              return mediaUIDLeft == mediaUIDRight
          }

          return lhs.likeUID == rhs.likeUID
      }
这意味着,如果要通过
mediaUID
进行检查,只需比较两个对象即可。如果要通过likeUID进行检查,只需更改其中一个对象的变量即可

示例

let a = NotificationInformation(type: "foo", mediaUID: "123", commentUID: "111")
let b = NotificationInformation(type: "bar", mediaUID: "123", commentUID: "111")

NotificationInformation.compareFields = .mediaUID
if a == b {
    print("same mediaUID")
}

NotificationInformation.compareFields = [.mediaUID, .commentUID]
if a == b {
    print("same mediaUID and commentUID")
}
extension NotificationInformation {
    func fetchNotificationsRemoved(query: DatabaseQuery) {
        NotificationInformation.observeNewNotificationsChildRemoved(query: query) { [weak self] newNotification in
            guard let strongSelf = self else {return}
            guard let notification = newNotification else {return}
            guard let index = strongSelf.notificationsArray.index(of: notification) else {return}
            strongSelf.notificationsArray.remove(at: index)
            let visibleIndexes = strongSelf.tableView.indexPathsForVisibleRows
            let indexPathOfRemovedNotification = IndexPath(row: index, section: 0)
            if let indexes = visibleIndexes, indexes.contains(indexPathOfRemovedNotification) {
                strongSelf.tableView.deleteRows(at: [indexPathOfRemovedNotification], with: .fade)
            }
        }
    }
}

您可以检查
NotificationInformation
对象的
type
属性,并根据该属性比较对象

extension NotificationInformation: Equatable {
    static func == (lhs: NotificationInformation, rhs: NotificationInformation) -> Bool {
        guard lhs.type == rhs.type  else {
            print("Types of lhs and rhs are not same ")
            return false
        }
        switch lhs.type {
        case "like": return lhs.likeUID == rhs.likeUID
        case "media": return lhs.mediaUID == rhs.mediaUID
        case "commentUID": return lhs.commentUID == rhs.commentUID
        default: return false
        }
    }
}


您可以对
类型
属性使用
enum

class NotificationInformation {
    enum NotificationType: String {
        case like
        case media
        case commentUID
    }
    let type: NotificationType
    let mediaUID: String?
    let commentUID: String?
    let likeUID:String?
}

extension NotificationInformation: Equatable {
    static func == (lhs: NotificationInformation, rhs: NotificationInformation) -> Bool {
        guard lhs.type == rhs.type  else {
            print("Types of lhs and rhs are not same ")
            return false
        }
        switch lhs.type {
        case .like: return lhs.likeUID == rhs.likeUID
        case .media: return lhs.mediaUID == rhs.mediaUID
        case .commentUID: return lhs.commentUID == rhs.commentUID
        }
    }
}

用法

let a = NotificationInformation(type: "foo", mediaUID: "123", commentUID: "111")
let b = NotificationInformation(type: "bar", mediaUID: "123", commentUID: "111")

NotificationInformation.compareFields = .mediaUID
if a == b {
    print("same mediaUID")
}

NotificationInformation.compareFields = [.mediaUID, .commentUID]
if a == b {
    print("same mediaUID and commentUID")
}
extension NotificationInformation {
    func fetchNotificationsRemoved(query: DatabaseQuery) {
        NotificationInformation.observeNewNotificationsChildRemoved(query: query) { [weak self] newNotification in
            guard let strongSelf = self else {return}
            guard let notification = newNotification else {return}
            guard let index = strongSelf.notificationsArray.index(of: notification) else {return}
            strongSelf.notificationsArray.remove(at: index)
            let visibleIndexes = strongSelf.tableView.indexPathsForVisibleRows
            let indexPathOfRemovedNotification = IndexPath(row: index, section: 0)
            if let indexes = visibleIndexes, indexes.contains(indexPathOfRemovedNotification) {
                strongSelf.tableView.deleteRows(at: [indexPathOfRemovedNotification], with: .fade)
            }
        }
    }
}

您可以检查
NotificationInformation
对象的
type
属性,并根据该属性比较对象

extension NotificationInformation: Equatable {
    static func == (lhs: NotificationInformation, rhs: NotificationInformation) -> Bool {
        guard lhs.type == rhs.type  else {
            print("Types of lhs and rhs are not same ")
            return false
        }
        switch lhs.type {
        case "like": return lhs.likeUID == rhs.likeUID
        case "media": return lhs.mediaUID == rhs.mediaUID
        case "commentUID": return lhs.commentUID == rhs.commentUID
        default: return false
        }
    }
}


您可以对
类型
属性使用
enum

class NotificationInformation {
    enum NotificationType: String {
        case like
        case media
        case commentUID
    }
    let type: NotificationType
    let mediaUID: String?
    let commentUID: String?
    let likeUID:String?
}

extension NotificationInformation: Equatable {
    static func == (lhs: NotificationInformation, rhs: NotificationInformation) -> Bool {
        guard lhs.type == rhs.type  else {
            print("Types of lhs and rhs are not same ")
            return false
        }
        switch lhs.type {
        case .like: return lhs.likeUID == rhs.likeUID
        case .media: return lhs.mediaUID == rhs.mediaUID
        case .commentUID: return lhs.commentUID == rhs.commentUID
        }
    }
}

用法

let a = NotificationInformation(type: "foo", mediaUID: "123", commentUID: "111")
let b = NotificationInformation(type: "bar", mediaUID: "123", commentUID: "111")

NotificationInformation.compareFields = .mediaUID
if a == b {
    print("same mediaUID")
}

NotificationInformation.compareFields = [.mediaUID, .commentUID]
if a == b {
    print("same mediaUID and commentUID")
}
extension NotificationInformation {
    func fetchNotificationsRemoved(query: DatabaseQuery) {
        NotificationInformation.observeNewNotificationsChildRemoved(query: query) { [weak self] newNotification in
            guard let strongSelf = self else {return}
            guard let notification = newNotification else {return}
            guard let index = strongSelf.notificationsArray.index(of: notification) else {return}
            strongSelf.notificationsArray.remove(at: index)
            let visibleIndexes = strongSelf.tableView.indexPathsForVisibleRows
            let indexPathOfRemovedNotification = IndexPath(row: index, section: 0)
            if let indexes = visibleIndexes, indexes.contains(indexPathOfRemovedNotification) {
                strongSelf.tableView.deleteRows(at: [indexPathOfRemovedNotification], with: .fade)
            }
        }
    }
}

第一个例子有一个问题。如果有多个函数试图同时将
静态var compareFields
设置为不同的值,则它将被损坏。示例:在
viewdiload
中,我将有几个数据库观察者
通知信息。observewnnotificationschild已删除(查询:查询)
通知信息。observewnnotificationschild已添加(查询:查询)
通知信息。observewnnotificationschild已更改(查询:查询)
是,这可能是多线程的问题。如果您限制更改
compareFields
并将比较结果与主线程进行比较,您就可以了。您是否也可以为这种情况提供解决方案?感谢第一个例子中的一个问题。如果有多个函数试图同时将
静态var compareFields
设置为不同的值,则它将被损坏。示例:在
viewdiload
中,我将有几个数据库观察者
通知信息。observewnnotificationschild已删除(查询:查询)
通知信息。observewnnotificationschild已添加(查询:查询)
通知信息。observewnnotificationschild已更改(查询:查询)
是,这可能是多线程的问题。如果您限制更改
compareFields
并将比较结果与主线程进行比较,您就可以了。您是否也可以为这种情况提供解决方案?谢谢