4

Trying to get the index of an array ([AnyObject]). What's the part that I'm missing?

extension PageViewController : UIPageViewControllerDelegate {
      func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [AnyObject]) {
        let controller: AnyObject? = pendingViewControllers.first as AnyObject?
        self.nextIndex = self.viewControllers.indexOf(controller) as Int?
      }
    }

I have tried with Swift 1.2 this approach:

func indexOf<U: Equatable>(object: U) -> Int? {
    for (idx, objectToCompare) in enumerate(self) {
      if let to = objectToCompare as? U {
        if object == to {
          return idx
        }
      }
    }
    return nil
  }

Type 'AnyObject?' does not conform to protocol 'Equatable' Cannot assign to immutable value of type 'Int?'

Community
  • 1
  • 1
el.severo
  • 2,202
  • 6
  • 31
  • 62

2 Answers2

5

We need to cast the object we're testing to a UIViewController, since we know that are array of controllers is holding UIViewControllers (and we know that UIViewControllers conform to Equatable.

extension PageViewController : UIPageViewControllerDelegate {
    func pageViewController(pageViewController: UIPageViewController, willTransitionToViewControllers pendingViewControllers: [AnyObject]) {
        if let controller = pendingViewControllers.first as? UIViewController {
            self.nextIndex = self.viewControllers.indexOf(controller)
        }
    }
}

The logic behind the error is that in order for the indexOf method to compare the object you pass in, it must compare them using the == operator. The Equatable protocol specifies that the class has implemented this function, so this is what indexOf requires its arguments conform to.

Objective-C doesn't have this same requirement, but the actual Objective-C implementation ends up meaning that the argument is compared with objects in the array using the isEqual: method (which NSObject and therefore all Objective-C classes implement).

nhgrif
  • 61,578
  • 25
  • 134
  • 173
0

You have to cast the viewController property to an Array object:

if let controllers = self.viewControllers as? [UIViewController] {
    self.nextIndex = controllers.indexOf(controller)
}
Tim Specht
  • 3,068
  • 4
  • 28
  • 46
  • @nhgrif why would that be expensive? – Tim Specht Aug 19 '15 at 12:47
  • Sorry... this particular part might be necessary if `self.viewControllers` isn't already declared as a `[UIViewController]` (it's not clear from the question). But you missed the part where we need to cast `controller` to a `UIViewController`, as my answer describes. – nhgrif Aug 19 '15 at 12:48
  • Actually, upon a second read of the question, casting the array itself is entirely unnecessary. Look at the implementation of `indexOf` that's being used. – nhgrif Aug 19 '15 at 12:53