2017-06-11 7 views
3

配列メソッドindex(of:)を呼び出す際に問題があります。 MyClassUIViewControllerから継承し、MyDelegateプロトコルに準拠しています。Swift 4 'index'を引数リストで指定することはできません

//self.viewControllers: [(UIViewController & MyDelegate)] 
guard let myController = viewController as? MyClass, 
let index = self.viewControllers.index(of: myController) else {return} 

、私はエラーを取得する:

Cannot invoke 'index' with an argument list of type '(of: (UIViewController & MyDelegate))'

どのように私はこの問題を解決するため、拡張子でindex(of:)を実装するよりもよりよい解決策はありますか?

extension Array where Element == (UIViewController & MyDelegate) { 
    func index(of: Element) -> Int? { 
     for i in 0..<self.count { 
      if self[i] == of { 
       return i 
      } 
     } 
     return nil 
    } 
} 

答えて

3

これはほぼ確実にそのプロトコル(別名。existentials)don't conform to themselves事実の単なる延長です。したがって、があっても、class existentialUIViewController & MyDelegateEquatableに準拠しません。

したがってindex(of:)CollectionEquatableを持つ要素で呼び出されることに制約されているので、あなたは[UIViewController & MyDelegate]でそれを呼び出すことはできません。ここで

は、より多くの最小限の例です:

protocol P {} 
class Foo : P {} 

func foo<T : P>(_ t: T) {} 

let f: (Foo & P) = Foo() 
foo(f) // Cannot invoke 'foo' with an argument list of type '((Foo & P))' 

Foo & PFooがないにも関わらず、Pに準拠していないと我々はfoo(_:)への引数としてfを渡すことはできません。しかし実際には、これは、現実のが常にに準拠する必要がある明確なケースであるはずです。そこで、私は先に進んでfiled a bugとなりました。

固定されるまで、簡単な解決策はただのコンクリートの型に中間キャストを行うことです - ので、私たちの例では、私たちが行うことができます。

foo(f as Foo) 

とあなたの例では、あなたが行うことができます。

let index = (self.viewControllers as [UIViewController]).index(of: myController) 
+0

私は、拡張子のないルートクラスの配列を持ち、 'index(of:)'を使うときに同じエラーが発生しています。 NSObjectから継承するルートクラスを作成すると、すべて正常に動作します。それはなぜですか? – jjatie

+1

@jjatieあなたのルートクラスが 'Equatable'に準拠していない場合のように聞こえます。' NSObject'から継承すると、適合性が得られます(これはデフォルトでIDに基づいています)。あなたのクラスは 'Equatable'に準拠する必要があります。この場合、' NSObject'から継承する必要はありません。 – Hamish

+0

愚かな私!ありがとうございました。 – jjatie

関連する問題