当我扩展 CollectionType 时,Swift 不会调用我的“==”运算符重载

Posted

技术标签:

【中文标题】当我扩展 CollectionType 时,Swift 不会调用我的“==”运算符重载【英文标题】:Swift doesn't call my "==" operator overload when I extend CollectionType 【发布时间】:2016-02-09 19:03:34 【问题描述】:

我有一个继承自 NSManagedObject 的自定义类 (VotingOption),有时我想检查数组中的某些投票选项是否重复。我试图使我的代码尽可能通用。这是我为扩展 CollectionType 协议所做的:

extension CollectionType where Self.Generator.Element : Equatable 

    var duplicates: [Self.Generator.Element]
        return = self.filter  element in
            return self.filter  $0 == element .count != 1
        
    

    var hasDuplicates: Bool 
        return (self.duplicates.count != 0)
    

这就像一个魅力,除了它没有使用全局函数:

func ==(lhs: VotingOption, rhs: VotingOption) -> Bool 
     return (lhs.location?.title.lowercaseString == rhs.location?.title.lowercaseString) && (lhs.startDate == rhs.startDate)

当我做这样的事情时:

let temp: [VotingOption] = votingOptions?.array as? [VotingOption]
if temp.hasDuplicates 
     //do something

当我像这样在 VotingOption 中扩展 isEqual 时:

class VotingOption: NSManagedObject 

    override func isEqual(object: AnyObject?) -> Bool 

        if let rhs = object as? VotingOption 
            return (self.location?.title.lowercaseString == rhs.location?.title.lowercaseString) && (self.startDate == rhs.startDate)
         else 
            return false
        
    
    ...
    ...
    ... rest of class

应用程序崩溃并指向 AppDelegate 并出现“libc++abi.dylib:以未捕获的 NSException 类型异常终止”错误

如何告诉 CollectionType 中的“==”使用 VotingOption 的全局函数?

【问题讨论】:

起初 CollectionType 是协议,而不是类!你剩下的问题不是很清楚,至少对我来说。您的期望是什么?为什么? VotingOption 是否继承自 NSObject?在这种情况下,您必须覆盖isEqual,请参阅NSObject subclass in Swift: hash vs hashValue, isEqual vs ==。 @MartinR 是的,它继承自 NSObject。我试过覆盖 isEqual 但它一直在崩溃。我已经编辑了这个问题。请查看添加内容 好的,所以这是一个 NSManagedObject 子类。文档声明您不得在 NSManagedObject 子类上覆盖 isEqual:。看来你倒霉了…… 你能提供一个链接来证实这一点吗? 【参考方案1】:

这是一个实现duplicateshasDuplicates 两次的解决方案,一次用于Equatable 元素,一次用于VotingOptions 类。为了尽可能减少代码重复,我定义了一个用于查找重复的通用实现,它允许您传递一个比较两个元素的函数/闭包:

extension CollectionType 

    func findDuplicates(checkEqual: (Self.Generator.Element, Self.Generator.Element) -> Bool) -> [Self.Generator.Element]
        return self.filter  element in
            return self.filter  checkEqual($0, element) .count != 1
        
    


extension CollectionType where Self.Generator.Element : Equatable 

    var duplicates: [Self.Generator.Element]
        return self.findDuplicates(==)
    

    var hasDuplicates: Bool 
        return (self.duplicates.count != 0)
    


extension CollectionType where Self.Generator.Element : VotingOption 

    var duplicates: [Self.Generator.Element]
        return self.findDuplicates lhs, rhs in
            return (lhs.location?.title.lowercaseString == rhs.location?.title.lowercaseString) && (lhs.startDate == rhs.startDate)
        
    

    var hasDuplicates: Bool 
        return (self.duplicates.count != 0)
    

【讨论】:

谢谢!实际上我最终得到了一个不同的实现(有点类似于你)。我会接受你的回答,因为它最接近我的需要。主要的是它不像我需要的那样“通用”。我会更新我的问题【参考方案2】:

感谢所有帮助过的人。我将在这里发布最终实现: 基本上使用“equals”方法创建了一个新协议“Identity”,该方法基本上是“==”,最后为实现“Identity”的 NSManagedObjects 添加了一个通用扩展,该扩展基本上在“equals”方法中执行“==”。但是在“VotingOption”中,我已经根据我的特定需求覆盖了这个函数。最后,在“元素”为“身份”的地方扩展了集合类型。而不是 "==" 它调用 "equals" 方法:)

protocol Identity 
     func equals(rhs: Self) -> Bool


extension Identity where Self: NSManagedObject 
     func equals(rhs: Self) -> Bool 
          return self == rhs
     


extension CollectionType where Self.Generator.Element : Identity 

    var duplicates: [Self.Generator.Element] 

        return self.filter  element in
            return self.filter  $0.equals(element) .count != 1
        
    

    var hasDuplicates: Bool 
        return (self.duplicates.count > 0)
    


class VotingOption: NSManagedObject, Identity 

    func equals(rhs: VotingOption) -> Bool 

    //... implementation here
    

【讨论】:

以上是关于当我扩展 CollectionType 时,Swift 不会调用我的“==”运算符重载的主要内容,如果未能解决你的问题,请参考以下文章

symfony 3.4.14 collectionType编辑和删除问题

Symfony 4.4如何使用collectionType从0个字段开始

Symfony5 handleRequest 更新原始 collectionType 对象

在 CollectionType Admin 中获取父实体 ID

在 SWI Prolog 中使用 process_create/3 使用命令提示符或 shell 时出错

如何在Linux上安装swi Prolog的图形化调试器(ubuntu)