You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义NSTextLocation的NSTextRange如何正确比较相等性?

自定义NSTextLocation的NSTextRange相等性比较问题

当使用自定义NSTextLocation实现的NSTextRange调用isEqual(to:)方法时,即使起始和结束位置通过compare(_:)返回.orderedSame,也会判定为不相等。如何正确比较这类范围的相等性?

问题代码示例

class Location: NSObject, NSTextLocation {
    let value: Int

    func compare(_ location: NSTextLocation) -> ComparisonResult {
        guard let location = location as? Location else {
            fatalError("Expected Location")
        }

        if self.value == location.value {
            return .orderedSame
        } else if self.value < location.value {
            return .orderedAscending
        } else {
            return .orderedDescending
        }
    }

    init(_ value: Int) {
        self.value = value
    }
}

let textRange1 = NSTextRange(location: Location(1), end: Location(2))!
let textRange2 = NSTextRange(location: Location(1), end: Location(2))!

print("startLocations are equal: \(textRange1.location.compare(textRange2.location) == .orderedSame)")
print("endLocations are equal: \(textRange1.endLocation.compare(textRange2.endLocation) == .orderedSame)")
print("ranges are equal: \(textRange1.isEqual(to: textRange2))")

问题原因

NSTextRange的isEqual(to:)方法内部并非使用compare(_:)判断位置相等,而是直接调用NSObject的isEqual(_:)方法。默认的isEqual(_:)比较的是对象的内存地址,因此即使两个Location实例的value相同,也是不同的对象实例,导致NSTextRange判定为不相等。

解决方案

给自定义的Location类重写isEqual(_:)方法,根据value判断相等性;同时重写hash方法(这是NSObject子类遵循相等性约定的最佳实践):

class Location: NSObject, NSTextLocation {
    let value: Int

    func compare(_ location: NSTextLocation) -> ComparisonResult {
        guard let location = location as? Location else {
            fatalError("Expected Location")
        }

        if self.value == location.value {
            return .orderedSame
        } else if self.value < location.value {
            return .orderedAscending
        } else {
            return .orderedDescending
        }
    }
    
    override func isEqual(_ object: Any?) -> Bool {
        guard let other = object as? Location else {
            return false
        }
        return self.value == other.value
    }
    
    override var hash: Int {
        return value.hashValue
    }

    init(_ value: Int) {
        self.value = value
    }
}

let textRange1 = NSTextRange(location: Location(1), end: Location(2))!
let textRange2 = NSTextRange(location: Location(1), end: Location(2))!

print("startLocations are equal: \(textRange1.location.compare(textRange2.location) == .orderedSame)")
print("endLocations are equal: \(textRange1.endLocation.compare(textRange2.endLocation) == .orderedSame)")
print("ranges are equal: \(textRange1.isEqual(to: textRange2))") // 现在会输出true

结果验证

修改后运行代码,textRange1.isEqual(to: textRange2)会返回true,符合预期的相等性判断。

内容的提问来源于stack exchange,提问作者georgemp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 22:33:23