如何从数组中删除特定对象? [复制]

Posted

技术标签:

【中文标题】如何从数组中删除特定对象? [复制]【英文标题】:How to remove specific object from array? [duplicate] 【发布时间】:2017-04-08 14:55:04 【问题描述】:

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

protocol MyDelegate 


private var delegates = [MyDelegate]()
...
...
func removeDelegate(_ delegate: MyDelegate) 
    if let index = self.delegates.index(where:  $0 == delegate ) 
        log.trace("Removing delegate \(delegate)");
        self.delegates.remove(at: index)
    

    有没有更简单的方法来做到这一点?

    此条件“ $0 == delegate ”导致错误“无法将类型 '(OptionalNilComparisonType) -> Bool' 的值转换为预期的参数类型 '( ) -> 布尔'"。我怎样才能解决这个问题?我试过添加?和 !但仍然没有完全理解 Swift 的可选概念。

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

【问题讨论】:

代理应该是类的实例吗? 然后你可以定义一个“类协议”protocol MyDelegate: class 并使用身份运算符进行比较:index(where: $0 === delegate ) 【参考方案1】:
    有没有更简单的方法来做到这一点?

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

func removeDelegate(_ delegate: MyDelegate) 
    delegates.index(where:  $0 == delegate)
        .map  delegates.remove(at: $0) 

如果没有找到这样的delegate 对象,则上面的表达式只会返回nil(未捕获的结果)。


这个条件“ $0 == delegate ”给出导致错误, “无法将 '(OptionalNilComparisonType) -> Bool' 类型的值转换为 预期的参数类型'() -> Bool'”。我该如何解决这个问题?我试过了 添加?!,但仍不能完全理解Swift 的可选 概念。

这是 Swift 中一种模糊错误消息的又一个例子。核心错误是MyDelegate没有定义==操作符(不符合Equatable)。

但是,在您进行编辑后,您显示MyDelegate 是一个协议,因此如果您让它符合Equatable,您将无法(因为它将包含Self 类型要求)使用@ 987654345@ 作为具体类型(仅作为泛型上的类型约束)。

如果您的具体委托对象是引用对象 (class),并且您想在测试的意义上测试对象相等性是否都引用同一个对象(对象引用),您可以使用 @987654321 @ 可用于类实例。将MyDelegate(在您的编辑后将其显示为协议)限制为仅类,

protocol MyDelegate: class  /* ... */ 

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

func removeDelegate(_ delegate: MyDelegate) 
    delegates.index(where:  ObjectIdentifier($0) == ObjectIdentifier(delegate) )
        .map  delegates.remove(at: $0) 

查看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 在上述问题的 cmets 中所提到的,您也可以直接将 === 标识运算符用于类实例,而不是通过 ObjectIdentifier

func removeDelegate(_ delegate: MyDelegate) 
    delegates.index(where:  $0 === delegate )
        .map  delegates.remove(at: $0) 

为了完整起见,我们可以通过查看swift/stdlib/public/core/Equatable.swift 来验证=== 使用与== 运算符相同的Builtin 方法ObjectIdentifier

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
  

【讨论】:

没有像 java 和 c# 中的默认对象相等的 Swift 概念吗? @RichAmberale 一般来说,没有。 Object​Identifier 可用于类实例,因此如果您将 MyDelegate (在编辑后将其显示为协议)限制为仅类,您可以测试 ObjectIdentifier:s 的 $0 的相等性和上面的delegate。这实质上是测试两者是否引用(对象引用)到同一个对象,而不是在某些预定义的== 运算符的意义上它们是否相等。 @MartinR 感谢您的链接!我在ObjectIdentifier 的源代码中看到了相同的评论部分,但正在四处寻找=== 的实际实现(以验证它很可能调用相同的Builtin 方法)。 @RichAmberale 乐于提供帮助。这可能是个人喜好,但我自己在使用 Swift 时通常会避免使用 Obj-C 功能,所以我自己可能更喜欢 === / ObjectIdentifier 而不是 NSObjectProtocol:s isEqual(...) 方法。跨度> 感谢您的链接,我已经更新了其他答案。 - 我不知道。从github.com/apple/swift/blob/master/include/swift/AST/… 看来,似乎没有必要:“CastToUnknownObject 具有类型 (T) -> Builtin.UnknownObject。”和“BridgeToRawPointer 具有类型 (T) -> Builtin.RawPointer”——但我对“内置 SIL 操作”没有更深入的了解 :)

以上是关于如何从数组中删除特定对象? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何从 Swift 数组中删除这个对象? [复制]

如何使用 ES6 扩展运算符和剩余运算符从数组或对象中删除特定元素

如何通过typescript中的对象数组删除特定对象

如何删除 mongodb 特定文档中的数组中的项目? [复制]

使用索引从对象数组中删除对象? [复制]

从对象数组中删除最后一个对象。 [复制]