2016-11-13 12 views
0

汎用補完ハンドラの作成方法を理解しようとしています。下の例は、 "内部"の汎用補完ハンドラと、同じ汎用の補完ハンドラを示しています。私が "外部"フォームでそれを行うことができるのであれば、それを作成できます。問題は、私が完了ハンドラにinternalCompletion<T: MyEnum>...の相当物を書く方法を知らないことです。私はexternalCompletionの機能を書いています。それは、func externalCompletion(_ completer<T: MyEnum>: ((T) -> Void) where T: Hashable))の行に沿ったものですが、明らかに正しくありません。私がしようとしていることは可能ですか?私の見方は、完了ハンドラが一般的なままではいけないということです。機能レベルでは常に型のキャストが必要です。つまり、私の例では目的を破ってしまいます(つまり、func externalCompletetion<T: MyEnum>(_ completer: ((T) -> Void)) where T: Hashable、これはEnumA、 EnumB、およびEnumC、すべての3つでコンプリータを実行することができない。)Swift汎用補完ハンドラ

typealias MyEnumKeyedData<T: MyEnum> = [T: String] where T: Hashable 

// MARK : - MyEnum Protocol 

protocol MyEnum { 
    static func all<T: MyEnum>(_:T.Type) -> [T] where T: Hashable 
    static var all: [MyEnum] { get } 
} 
extension MyEnum { 
    static func all<T: MyEnum>(_:T.Type) -> [T] where T: Hashable { return Self.all as! [T] } 
} 

// MARK : - My enums 

enum EnumA: MyEnum { 
    case first 
    static var all: [MyEnum] { return [EnumA.first]} 
} 
enum EnumB: MyEnum { 
    case first 
    static var all: [MyEnum] { return [EnumB.first]} 
} 
enum EnumC: MyEnum { 
    case first 
    static var all: [MyEnum] { return [EnumC.first]} 
} 

// MARK : - MyEnum Data Iterator 

class MyDataEnumIterator { 
    var dataA: MyEnumKeyedData<EnumA> = [:] 
    var dataB: MyEnumKeyedData<EnumB> = [:] 
    var dataC: MyEnumKeyedData<EnumC> = [:] 

    func updateData<T: MyEnum>(_ key: T, _ value: String) where T: Hashable { 
    switch T.self { 
    case is EnumA.Type: dataA[key as! EnumA] = value 
    case is EnumB.Type: dataB[key as! EnumB] = value 
    case is EnumC.Type: dataC[key as! EnumC] = value 
    default: fatalError("Enum does not exist") 
    } 
    } 

    // Internal (This works) 

    func internalEnumIterator() { 
    for key in EnumA.all(EnumA.self) { internalCompletion(key) } 
    for key in EnumB.all(EnumB.self) { internalCompletion(key) } 
    for key in EnumC.all(EnumC.self) { internalCompletion(key) } 
    } 

    func internalCompletion<T: MyEnum>(_ key: T) where T: Hashable { 
    let value = "\(key)" 
    updateData(key, value) 
    } 

    // External (This obviously doesn't, just sketching the idea) 

    func externalEnumIterator(_ completer<T: MyEnum>: ((T) -> Void) where T: Hashable) { 
    for key in EnumA.all(EnumA.self) { completer(key) } 
    for key in EnumB.all(EnumB.self) { completer(key) } 
    for key in EnumC.all(EnumC.self) { completer(key) } 
    } 
} 

// MARK : - Test cases (internal works, external does not, just sketching example) 

let iterator = MyDataEnumIterator() 
iterator.externalEnumIterator({ <T: MyEnum> (T) where T: Hashable in 
    let value = "\(key)" 
    iterator.updateData(key, value) 
}) 
iterator.internalEnumIterator() 
+0

物事を簡素化するために最小限の例を挙げてください。 – Alexander

+0

これは非常に不必要に複雑です。これらのジェネリックは必要ありません。 – Alexander

+0

私は知っています。私はジェネリック薬で遊んでいた。実際にはあなたのソリューションは明らかに優れています –

答えて

1

ここでは、それがここ

typealias MyEnumKeyedData<T: MyEnum> = [T: String] where T: Hashable 

// MARK : - MyEnum Protocol 

protocol MyEnum { 
    static func all<T: MyEnum>(_:T.Type) -> [T] where T: Hashable 
    static var all: [MyEnum] { get } 
} 
extension MyEnum { 
    static func all<T: MyEnum>(_:T.Type) -> [T] where T: Hashable { return Self.all as! [T] } 
} 

// MARK : - My enums 

enum EnumA: MyEnum { 
    case first 
    static var all: [MyEnum] { return [EnumA.first]} 
} 
enum EnumB: MyEnum { 
    case first 
    static var all: [MyEnum] { return [EnumB.first]} 
} 
enum EnumC: MyEnum { 
    case first 
    static var all: [MyEnum] { return [EnumC.first]} 
} 

// MARK : - MyEnum Data Iterator 

class MyDataEnumIterator { 
    var dataA: MyEnumKeyedData<EnumA> = [:] 
    var dataB: MyEnumKeyedData<EnumB> = [:] 
    var dataC: MyEnumKeyedData<EnumC> = [:] 

    func updateData(_ key: MyEnum, _ value: String) { 
     switch key { 
     case let key as EnumA: dataA[key] = value 
     case let key as EnumB: dataB[key] = value 
     case let key as EnumC: dataC[key] = value 
     default: fatalError("Enum does not exist") 
     } 
    } 

    // Internal (This works) 

    func internalEnumIterator() { 
     for key in EnumA.all(EnumA.self) { internalCompletion(key) } 
     for key in EnumB.all(EnumB.self) { internalCompletion(key) } 
     for key in EnumC.all(EnumC.self) { internalCompletion(key) } 
    } 

    func internalCompletion<T: MyEnum>(_ key: T) where T: Hashable { 
     let value = "\(key)" 
     updateData(key, value) 
    } 

    func EnumIterator(_ compeltitionHandler: (MyEnum) -> Void) { 
     for key in EnumA.all(EnumA.self) { compeltitionHandler(key as MyEnum) } 
     for key in EnumB.all(EnumB.self) { compeltitionHandler(key as MyEnum) } 
     for key in EnumC.all(EnumC.self) { compeltitionHandler(key as MyEnum) } 
    } 
} 


let iterator = MyDataEnumIterator() 

iterator.EnumIterator{ key in 
    let value = "\(key)" 
    iterator.updateData(key, value) 
} 
iterator.internalEnumIterator() 

を軌道に乗るために必要な最小限の変更でコードの作業バージョンがされていますすべてのナンセンスを削除し、添字の構文を追加するコードの正常なバージョン:

// MARK : - MyEnum Protocol 

protocol MyEnum { 
    static func all() -> [MyEnum] 
} 

// MARK : - My enums 

enum EnumA: MyEnum { 
    case first 
    static func all() -> [MyEnum] { return [EnumA.first] } 
} 
enum EnumB: MyEnum { 
    case first 
    static func all() -> [MyEnum] { return [EnumB.first] } 
} 
enum EnumC: MyEnum { 
    case first 
    static func all() -> [MyEnum] { return [EnumC.first] } 
} 

// MARK : - MyEnum Data Iterator 

class MyDataEnumIterator { 
    var dataA = [EnumA: String]() 
    var dataB = [EnumB: String]() 
    var dataC = [EnumC: String]() 


    subscript(key: MyEnum) -> String? { 
     get { 
      switch key { 
      case let key as EnumA: return dataA[key] 
      case let key as EnumB: return dataB[key] 
      case let key as EnumC: return dataC[key] 
      default: fatalError("Enum does not exist") 
      } 
     } 
     set { 
      switch key { 
      case let key as EnumA: dataA[key] = newValue 
      case let key as EnumB: dataB[key] = newValue 
      case let key as EnumC: dataC[key] = newValue 
      default: fatalError("Enum does not exist") 
      } 
     } 
    } 

    func EnumIterator(_ body: (MyEnum) -> Void) { 
     EnumA.all().forEach(body); 
     EnumB.all().forEach(body); 
     EnumC.all().forEach(body); 
    } 
} 


let iterator = MyDataEnumIterator() 
iterator.EnumIterator{ 
    iterator[$0] = "\($0)" 
} 
関連する問題