首页 > 解决方案 > 为什么 containsObject 在 NSMutableSet 的 NSSet 副本上不起作用?

问题描述

我在创建可变集的集副本时遇到问题,然后对于(新)集副本的 containsObject 失败。例如:

NSString *sameID = @"XYZ";

然后在主线程/有时在不同的线程上:

[mutableSet addObject:sameID];
NSLog(@"adding Object: %@", sameID);

然后在后台线程上,总是在(我已经通过记录验证)添加了sameID之后:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    NSSet<NSString *> *newSet = self.mutableSet.copy;
    if ([newSet containsObject:sameID]) {
      // do stuff
    }
});

看到有断点:

1. po [newSet containsObject:sameID] // returns NO
2. po [self.mutableSet containsObject:sameID] // returns YES

我已经测试了相同 ID 字符串没有额外或隐藏的空格。AFAIK containsObject 用于包含 NSString 的集合使用 isEqual 如果字符串具有不同的指针,这无关紧要,对吧?

编辑:一些附加信息:添加到 mutableSet 的 NSString 发生在不同的线程上,但总是在创建 newSet 副本之前发生。创建和检查 newSet 是在后台线程上完成的,这就是我复制 mutableSet 的原因(我在日志记录中看到这总是在向 mutableSet 添加字符串之后)。所以我在日志语句中看到字符串(sameID)已添加到 mutableSet,然后在后台线程上我将 mutableSet 复制为一个集合并快速检查该集合是否有相同的字符串(sameID),但它不存在。

Edit2:我已经测试了下面的代码并且它通过了,但是当我尝试实现与上述相同的解决方案时,它仍然具有相同的结果(mutableSet 包含字符串但 newSet 不包含)。

import XCTest
import Foundation

class CustomObj: NSObject {
    let id: String

    init(id: String) { self.id = id }

    override func isEqual(_ object: Any?) -> Bool {
        if let other = object as? CustomObj {
            return self.id == other.id
        } else {
            return false
        }
    }

    override var hash: Int {
        return id.hashValue
    }
}

func testSetStrings() {
    let set = NSMutableSet(object: CustomObj(id: "String-1"))
    let copySet: Set<CustomObj> = set.copy() as! Set<CustomObj>

    let customObjForTest = CustomObj(id: "String-1")

    XCTAssertTrue(set.contains(customObjForTest), "Does Not Contain")
    XCTAssertTrue(copySet.contains(customObjForTest), "Copy Does Not Contain")
}

testSetStrings()

标签: iosobjective-cnsstringnssetnsmutableset

解决方案


推荐阅读