2017-07-26 14 views
1

質問があります(多分型消去に関して)。次のシナリオを想像:Swift Collection of Associated Typeに準拠したプロトコル

public protocol DataItem { 

    associatedtype T 
    var action: ((_ item: T) -> Void)? {get} 
} 

struct UserItem: DataItem { 

    typealias T = UserItem 

    // Custom Properties 
    let name: String 

    // Protocol: DataItem 
    let action: ((T) -> Void)? 
} 

struct DriverItem: DataItem { 

    typealias T = DriverItem 

    // Custom Properties 
    let licenseNumber: String 

    // Protocol: DataItem 
    let action: ((T) -> Void)? 
} 

let items = [ 
    UserItem(name: "Dexter", action: { (item) in print(item.name)}), 
    DriverItem(licenseNumber: "1234567890", action: { (item) in print(item.licenseNumber)}) 
] 

items.forEach { 
    $0.action?($0) 
} 

を私はのUITableViewCellの抽象データ項目であるとセルが選択されたときに呼び出されるアクション性を有しているのDataItemを持っています。私の質問は、DataItemオブジェクトの配列を作成し、このリストからアイテムを選択(または繰り返し)し、それぞれのアクションを呼び出して、UserItemの名前とDriverItemのライセンス番号を出力する方法です。しかし、コンパイラ上記のような実装でのアイテムのリストが唯一私がプロトコルのDataItemで宣言されたアクションを呼び出すことはできませんその方法

Heterogeneous collection literal could only be inferred to '[Any]'; add explicit type annotation if this is intentional

... [任意]タイプのものとすることができることを、次のメッセージを表示して文句を言います。私は型消去のまわりで私の頭をラップしようとしたが、

+0

これを行う方法はgetすでに入力されたが、これと同様に、完全なdidntのを使用することです'UserItem'(/' DriverItem /)の 'UserItem'(/' DriverItem /)自体は_instance_クロージャ 'action'がそれを所有するインスタンスと同じ型の単一の引数を取ることを意味します。これは意図されたものなのでしょうか?与えられた 'UserItem'インスタンスは、' UserItem'の_another_インスタンスに対してアクションを実行することですか?私はアクションがセカンダリの外部インスタンスではなくインスタンス自体で実行されると期待していますが、これは意図した設計の選択肢かもしれません。とにかく、もしそうなら、あなたは 'associatedtype'を緩め、' T'の代わりに 'Self'を使うことができます。 – dfri

+0

UIControlsのターゲット/アクションと同じように、送信メソッドをアクションメソッドに提供することを意図しています。送信者はアイテムそのものです。私は、アクションメソッドで具体的な型(nameやlicenseNumberなど)の機能を使用することが可能であることを望んでいます。重要なのは、アイテムは、具体的な型についてはわからないDataSourceオブジェクト内にのみ存在することです。そのため、私は具体的なタイプの機能に直接アクセスできません。私はあなたのアプローチをできるだけ早く試みます。 – blackjacx

+0

Arg .... Tの代わりにSelfを使用すると、同じことが起こります。 'Protocol 'DataItem'は、自己または関連付けられた型要件を持つため、汎用制約としてのみ使用できます。この動作タイプのため、消しゴムが書き込まれます。しかし、私はそれを正しく行う方法を理解していない...誰かアイデア? – blackjacx

答えて

-1

それは追加の要件とそれは難しいことではありません...誰もが解決策を思い付く場合

が幸せだろう...まだそれを理解できませんでした:

struct UserItem { 
    let name: String 

    func action() { 
     print(name) 
    } 
} 

struct DriverItem { 
    let licenseNumber: String 

    func action() { 
     print(licenseNumber) 
    } 
} 

let data = UserItem(name: "Test") 
let closure = { print("Some object data \(data.name)") } 
let items = [ 
    UserItem(name: "Dexter").action, 
    DriverItem(licenseNumber: "1234567890").action, 
    closure 
] 

items.forEach { 
    $0() 
} 
+0

アクションクロージャは、静的関数ではなく外部から設定できるクロージャと見なされます。 – blackjacx

+0

正しいシグネチャを持つクロージャを配列に配置することができます。別のパラメータをとるクロージャは使用できません。適切な配列にtitle(例)とvoid-closureを持つ構造体を置くこともできます。 – Tino

-1

エラーがちょうど項目にタイプを追加するように要求されます:私はあなたが完了ブロックwhilを呼び出すことができるかどうかわからないので、これは複数のエラーにつながることはありません場合

let items: Array<Any> = [ 
    UserItem(name: "Dexter", action: { (item) in print(item.name)}), 
    DriverItem(licenseNumber: "1234567890", action: { (item) in print(item.licenseNumber)}) 
] 

わかりませんe配列を作成します。


編集

私が何をやろうとしていることは、変数が呼び出されたときにコールを取得すると思います。

var licenseNumber: String { 
    get { 
     print("doSomething!") 
     return self.licenseNumber 
    } 
} 

配列のようなものになる:あなた `associatedtype`ことそれはやや奇妙に見える

let items: Array<Any> = [ 
    UserItem(name: "Dexter"), 
    DriverItem(licenseNumber: "1234567890") 
] 
+0

はアクションブロックを呼び出すことができません... – blackjacx

+0

@blackjacx Iveは私の答えを編集しました –

+0

アイテムにはすべてのオブジェクトが含まれているので、 'items.forEach { $ 0.action?($ 0) } 'のようなアクションメソッドを呼び出すことはまだできませんあなたの場合。私はタイプ消しゴムパターンは私が検索するものだと思うが、私はこれを正しく実装する方法がわからない。 – blackjacx

関連する問題