2017-08-31 12 views
2

J'ai une Equatable classeANYOBJECT try jeté à assimilables

class Item: Equatable { 
    var value: AnyObject? 
    var title: String 
    init(title: String, value: AnyObject?) { 
     self.title = title 
     self.value = value 
    } 
    //Equatable 
    public static func ==(lhs: Item, rhs: Item) -> Bool { 
     return ((lhs.title == rhs.title) && (lhs.value === rhs.value)) 
    } 
} 

Mais je veux jeter essayer var value à assimilables, donc qui obtiennent des résultats assimilables doux

if let lValue = lhs.value as? Equatable, // Error 
    let rValue = rhs.value as? Equatable { // Error 
    valueEq = (lValue == rValue) 
} else { 
    valueEq = (lhs.value === rhs.value) 
} 

Ce code capture erreur de compilation à propos de Generic Equatable

Comment je s Je peux corriger Equatable pour cette classe?

UPD

Je veux utiliser mon Item dans UITableViewCell dans mon story-board. Je ne peux pas créer de générique UITableViewCell. Et si j'essaie faire comme point Generic<T: Equatable> classe, je serai obligé de spécifier les types dans mes cellules,

var items: [Item<OnlyThisHashableClass>] 

mais je veux utiliser l'article dans les cellules pour tous les objets

+0

Quel problème vous avez avec le code affiché? – rmaddy

+1

vous devez créer un type de valeur personnalisé conforme à Equatable. –

+0

Mettez à jour votre question avec le message d'erreur exact et complet, pas un résumé. – rmaddy

Répondre

1

Manière simple - classe reste non générique, générique uniquement init, et GenericInit méthode de création isEquals

class FieldItem: CustomStringConvertible, Equatable { 
    let value: Any? 
    let title: String 
    private let equals: (Any?) -> Bool 
    init<Value: Equatable>(title: String, value: Value?) { 
     func isEquals(_ other: Any?) -> Bool { 
      if let l = value, let r = other { 
       if let r = r as? Value { 
        return l == r 
       } else { 
        return false 
       } 
      } else { 
       return true 
      } 
     } 
     self.title = title 
     self.value = value 
     self.equals = isEquals 
    } 
    //CustomStringConvertible 
    var description: String { get { return title } } 
    //Equatable 
    public static func ==(lhs: FieldItem, rhs: FieldItem) -> Bool { 
     return ((lhs.title == rhs.title) && lhs.equals(rhs.value)) 
    } 

} 
1

Vous ne pouvez pas lancer AnyObject à un Equatable.

Ce que vous pouvez faire est de définir Item comme générique pour laquelle le value, Wrapped, doit être Equatable:

class Item<Wrapped: Equatable> { 
    var title: String 
    var value: Wrapped 

    init(title: String, value: Wrapped) { 
     self.title = title 
     self.value = value 
    } 
} 

extension Item: Equatable { 
    static func ==(lhs: Item, rhs: Item) -> Bool { 
     return lhs.title == rhs.title && lhs.value == rhs.value 
    } 
} 

Et, imaginons que vous avez une certaine classe, Foo, qui (a) n » t égalable; (b) est quelque chose que vous voulez envelopper dans un Item; et (c) vous voulez vraiment les définir pour être équitables sur la base de l'opérateur d'identité, ===. (J'avoue, je trouve cette notion, que vous appelez "soft equatable" notion assez troublante, mais je ne vais pas entrer dans cela ici.)

De toute façon, vous pouvez simplement faire votre classe Foo sur la base de la opérateur d'identité:

extension Foo: Equatable { 
    static func ==(lhs: Foo, rhs: Foo) -> Bool { 
     return lhs === rhs 
    } 
} 

Ou, si vous avez besoin de faire cela pour de nombreuses classes, vous pourriez même avoir un protocole pour cette identité-égalité, puis vos classes non assimilables pourraient simplement se conformer à ce qui suit:

protocol IdentityEquatable: class, Equatable { } 

extension IdentityEquatable { 
    static func ==(lhs: Self, rhs: Self) -> Bool { 
     return lhs === rhs 
    } 
} 

Puis toutes les classes que vous voulez wr ap dans un Item qui ne sont pas Equatable pourrait adopter ce comportement identitaire assimilables à une seule ligne de code à chaque:

extension Foo: IdentityEquatable { } 
extension Bar: IdentityEquatable { } 
extension Baz: IdentityEquatable { } 

En aparté, SE-0143 a été approuvé et tout en ne faisant pas partie de la langue encore , offre la promesse de condition dans les futures versions Conformance Swift, à savoir:

class Item<Wrapped> { 
    var title: String 
    var value: Wrapped 

    init(title: String, value: Wrapped) { 
     self.title = title 
     self.value = value 
    } 
} 

extension Item: Equatable where Wrapped: Equatable { 
    static func ==(lhs: Item, rhs: Item) -> Bool { 
     return lhs.title == rhs.title && lhs.value == rhs.value 
    } 
} 

dans ce cas, Item serait Equatable si et seulement si le Wrapped val ue était Equatable.Cela ne fait pas encore partie de la langue, mais il semble que ce sera dans une future version. C'est une solution élégante à ce problème (mais pas, il est vrai, votre idée de «soft equatable»).

+0

mais j'utilise mon 'Item' dans de nombreuses classes, par exemple dans' UITableViewCell' dans mon storyboard. Et si j'essaie de faire 'Item' comme classe générique, je serai obligé de spécifier les types dans mes cellules, mais je veux utiliser Item dans Cells comme classe de base (value - AnyObject) –