如何从数组中删除特定对象?

How to remove specific object from array?

如果调用者传入一个MyDelegate类型的对象,并且在数组中,我想将其从数组中移除。

protocol MyDelegate {
}

private var delegates = [MyDelegate]()
...
...
func removeDelegate(_ delegate: MyDelegate) {
    if let index = self.delegates.index(where: { [=10=] == delegate }) {
        log.trace("Removing delegate \(delegate)");
        self.delegates.remove(at: index)
    }
}
  1. 有没有更简单的方法来做到这一点?

  2. 这个条件“{ $0 == delegate }”导致错误 "Cannot convert value of type '(OptionalNilComparisonType) -> Bool' to expected argument type '() -> Bool'"。我怎样才能解决这个问题?我试过添加 ?和 !但仍然没有完全理解Swift的可选概念。

我正在使用 Xcode 8.2.1 和 Swift 3(?)。

  1. Is there a less complicated way to do this?

可以在访问delegates成员时省略self,并将index(where:)调用的结果索引烘焙到对Optionalmap 方法:

func removeDelegate(_ delegate: MyDelegate) {
    delegates.index(where: { [=10=] == delegate})
        .map { delegates.remove(at: [=10=]) }
}

如果没有找到这样的 delegate 对象,上面的表达式只是结果 nil(非捕获结果)。


This conditional, "{ [=23=] == delegate }", is giving causing the error, "Cannot convert value of type '(OptionalNilComparisonType) -> Bool' to expected argument type '() -> Bool'". How can I fix this? I've tried adding ? and ! but still not fully understanding Swift's optional concept.

这是 Swift 中另一种模糊错误消息的示例。核心错误是 MyDelegate 没有定义 == 运算符(不符合 Equatable)。

然而,在你的编辑之后,你显示 MyDelegate 是一个协议,所以如果你让它符合 Equatable,你将无法(因为它将包含一个 Self 类型要求)使用 MyDelegate 作为具体类型(仅作为泛型上的类型约束)。

如果您的具体委托对象是引用对象 (class),并且您想在测试两者是否引用同一对象(对象引用)的意义上测试对象相等性,您可以使用class 实例可用的 Object​Identifier。将 MyDelegate(在你编辑后你显示它是一个协议)限制为仅 classes,

protocol MyDelegate: class { /* ... */ }

并在上面的 index(where:) 调用中测试 ObjectIdentifier 的相等性:

func removeDelegate(_ delegate: MyDelegate) {
    delegates.index(where: { ObjectIdentifier([=12=]) == ObjectIdentifier(delegate) })
        .map { delegates.remove(at: [=12=]) }
}

查看 ObjectIdentifier 的源代码,我们发现这将比较两个 delegate 实例的底层原始 ptr 值;来自 swift/stdlib/public/core/ObjectIdentifier.swift:

public static func == (x: ObjectIdentifier, y: ObjectIdentifier) -> Bool {
  return Bool(Builtin.cmp_eq_RawPointer(x._value, y._value))
}

正如@MartinR 在对上述问题的评论中提到的,除了通过 ObjectIdentifier,您还可以直接对 class 实例使用 === 身份运算符。

func removeDelegate(_ delegate: MyDelegate) {
    delegates.index(where: { [=14=] === delegate })
        .map { delegates.remove(at: [=14=]) }
}

为了完整性,我们可以通过查看 [=] 来验证 === 使用与 ObjectIdentifier== 运算符相同的 Builtin 方法54=]:

public func === (lhs: AnyObject?, rhs: AnyObject?) -> Bool {
  switch (lhs, rhs) {
  case let (l?, r?):
    return Bool(Builtin.cmp_eq_RawPointer(
        Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(l)),
        Builtin.bridgeToRawPointer(Builtin.castToUnknownObject(r))
      ))
  case (nil, nil):
    return true
  default:
    return false
  }
}