为什么 UICollectionViewUpdateItem indexPathBeforeUpdate(类型为 NSIndexPath?)需要两个 ! 来解包

Why does the UICollectionViewUpdateItem indexPathBeforeUpdate (of type NSIndexPath?) require two !'s to unwrap

UICollectionViewLayout 包含函数 prepareForCollectionViewUpdates

func prepareForCollectionViewUpdates(_ updateItems: [AnyObject]!) // updateItems is an array of UICollectionViewUpdateItem

UICollectionViewUpdateItem 包含一个 属性 indexPathBeforeUpdate

var indexPathBeforeUpdate: NSIndexPath? { get }

我正在查看 CollectionViewLayout class 的一些代码,它是 UICollectionViewFlowLayout 的子 class,而 Xcode 需要两个 ! 来解包 indexPathBeforeUpdate(这是一个 属性,其 getter returns 一个 NSIndexPath?)。看起来这只需要一个 ! 来解包。相关代码:

class CollectionViewLayout: UICollectionViewFlowLayout {

  var insertIndexPaths = NSMutableArray()
  var deleteIndexPaths = NSMutableArray()

  override func prepareForCollectionViewUpdates(updateItems: [AnyObject]!) {
       super.prepareForCollectionViewUpdates(updateItems)

      deleteIndexPaths.removeAllObjects()
      insertIndexPaths.removeAllObjects()

      for update in updateItems {
        if update.updateAction == UICollectionUpdateAction.Delete {
          deleteIndexPaths.addObject(update.indexPathBeforeUpdate!!)   // <- I have a question here
        } else if update.updateAction == UICollectionUpdateAction.Insert {
          insertIndexPaths.addObject(update.indexPathAfterUpdate!!)           
        }
      }
    ...
    }
  }

如果我只用一个!展开 update.indexPathBeforeUpdate

 deleteIndexPaths.addObject(update.indexPathBeforeUpdate!)

我收到错误:

Value of optional type 'NSINdexPath?' not unwrapped; did you mean to use '!' or '?'?" 

我得到修复建议“插入 ! 有两个 !'s 解包更新。indexPathBeforeUpdate,代码运行正常。

为了调查,我在 for 循环中插入了一些变量:

for update in updateItems {
  var myUpdate = update  // option-click shows myUpdate is an AnyObject
  var indexPath1 = update.indexPathBeforeUpdate    // option-click shows indexPath1 is an NSIndexPath?!
  var indexPath2 = update.indexPathBeforeUpdate!   // option-click shows indexPath2 is an NSIndexPath?
  var indexPath3 = update.indexPathBeforeUpdate!!  // option-click shows indexPath3 is an NSIndexPath
...
}

按住 Option 键并单击变量会在上面的注释中显示每个变量的类型。

UICollectionViewUpdateItem 的文档显示 indexPathBeforeUpdate 是可选的 [=33] 时,为什么 Xcode 需要两个 ! 来展开 update.indexPathBeforeUpdate =] (NSIndexPath?)?

请注意,当您在 for-in 循环 属性 中为 update 拉起自动完成时,它如何 return 是可选的?那是因为您正在处理 [AnyObject] 的数组。 Swift 无法保证该对象将具有您要求的 属性,因此它会将其包装在一个 Optional.

如果你转换那个数组,你就没有双重解包问题(或者至少你已经将第一个力解包移动到转换中)。

for update in updateItems as! [UICollectionViewUpdateItem] {
    if update.updateAction == UICollectionUpdateAction.Delete {
        deleteIndexPaths.addObject(update.indexPathBeforeUpdate!)
    } else if update.updateAction == UICollectionUpdateAction.Insert {
        insertIndexPaths.addObject(update.indexPathAfterUpdate!)
    }
}

我猜 Apple 还没有时间审核这个 API。将来我希望方法签名更改为:

override func prepareForCollectionViewUpdates(updateItems: [UICollectionViewUpdateItem])

这将不再是问题。现在这只是我们必须处理的事情。