Comment créer un enum Swift Ssortingng disponible dans Objective-C?

J’ai cette énumération avec les valeurs Ssortingng , qui seront utilisées pour indiquer à une méthode API qui se connecte à un serveur quel type de serveur possède un message. J’utilise Swift 1.2, donc les énumérations peuvent être associées à Objective-C

 @objc enum LogSeverity : Ssortingng { case Debug = "DEBUG" case Info = "INFO" case Warn = "WARN" case Error = "ERROR" } 

Je reçois l’erreur

@objc enum type brut La chaîne n’est pas un type entier

Je n’ai pas réussi à trouver n’importe où qui dit que seuls les entiers peuvent être traduits en Objective-C depuis Swift. Est-ce le cas? Si oui, est-ce que quelqu’un a des suggestions de meilleures pratiques sur la façon de rendre quelque chose comme cela disponible dans Objective-C?

A partir des notes de version de Xcode 6.3 (emphase ajoutée):

Amélioration du langage rapide


Les énumérations rapides peuvent maintenant être exscopes vers Objective-C en utilisant l’atsortingbut @objc. @objc enums doit déclarer un type brut entier et ne peut pas être générique ou utiliser des valeurs associées. Étant donné que les énumérations Objective-C ne sont pas des espaces de noms, les cas d’énumération sont importés dans Objective-C en tant que concaténation du nom enum et du nom de la casse.

L’une des solutions consiste à utiliser le protocole RawRepresentable.

Il n’est pas idéal d’avoir à écrire les méthodes init et rawValue, mais cela vous permet d’utiliser cette énumération comme d’habitude dans Swift et Objective-C.

 @objc public enum LogSeverity: Int, RawRepresentable { case Debug case Info case Warn case Error public typealias RawValue = Ssortingng public var rawValue: RawValue { switch self { case .Debug: return "DEBUG" case .Info: return "INFO" case .Warn: return "WARN" case .Error: return "ERROR" } } public init?(rawValue: RawValue) { switch rawValue { case "DEBUG": self = .Debug case "INFO": self = .Info case "WARN": self = .Warn case "ERROR": self = .Error default: self = .Debug } } } 

Voici une solution qui fonctionne.

 @objc public enum ConnectivityStatus: Int { case Wifi case Mobile case Ethernet case Off func name() -> Ssortingng { switch self { case .Wifi: return "wifi" case .Mobile: return "mobile" case .Ethernet: return "ethernet" case .Off: return "off" } } } 

Voici comment travailler si vous voulez vraiment atteindre l’objective. Cependant, vous pouvez accéder aux valeurs d’énumération dans les objects acceptés par Objective C, et non en tant que valeurs d’énumération réelles.

 enum LogSeverity : Ssortingng { case Debug = "DEBUG" case Info = "INFO" case Warn = "WARN" case Error = "ERROR" private func ssortingng() -> Ssortingng { return self.rawValue } } @objc class LogSeverityBridge: NSObject { class func Debug() -> NSSsortingng { return LogSeverity.Debug.ssortingng() } class func Info() -> NSSsortingng { return LogSeverity.Info.ssortingng() } class func Warn() -> NSSsortingng { return LogSeverity.Warn.ssortingng() } class func Error() -> NSSsortingng { return LogSeverity.Error.ssortingng() } } 

Appeler :

 NSSsortingng *debugRawValue = [LogSeverityBridge Debug] 

Code pour Xcode 8, en utilisant le fait que Int fonctionne, mais que les autres méthodes ne sont pas exposées à Objective-C. C’est assez horrible en l’état …

 class EnumSupport : NSObject { class func textFor(logSeverity severity: LogSeverity) -> Ssortingng { return severity.text() } } @objc public enum LogSeverity: Int { case Debug case Info case Warn case Error func text() -> Ssortingng { switch self { case .Debug: return "debug" case .Info: return "info" case .Warn: return "warn" case .Error: return "error" } } } 

Si cela ne vous dérange pas de définir les valeurs dans (Objectif) C, vous pouvez utiliser la macro NS_TYPED_ENUM pour importer des constantes dans Swift.

Par exemple:

Fichier .h

 typedef NSSsortingng *const ProgrammingLanguage NS_TYPED_ENUM; FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageSwift; FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageObjectiveC; 

fichier .m

 ProgrammingLanguage ProgrammingLanguageSwift = "Swift"; ProgrammingLanguage ProgrammingLanguageObjectiveC = "ObjectiveC"; 

Dans Swift, ceci est importé en tant que struct tant que telle:

 struct ProgrammingLanguage: RawRepresentable, Equatable, Hashable { typealias RawValue = Ssortingng init(rawValue: RawValue) var rawValue: RawValue { get } static var swift: ProgrammingLanguage { get } static var objectiveC: ProgrammingLanguage { get } } 

Bien que le type ne soit pas un pont en tant que enum , il se sent très similaire à celui utilisé dans le code Swift.

Vous pouvez en savoir plus sur cette technique dans la section “Interaction avec les API C” de la documentation Utilisation de Swift avec Cocoa et Objective-C

Voici ce que j’ai imaginé. Dans mon cas, cette énumération était dans le contexte fournissant des informations pour une classe spécifique, ServiceProvider .

 class ServiceProvider { @objc enum FieldName : Int { case CITY case LATITUDE case LONGITUDE case NAME case GRADE case POSTAL_CODE case STATE case REVIEW_COUNT case COORDINATES var ssortingng: Ssortingng { return ServiceProvider.FieldNameToSsortingng(self) } } class func FieldNameToSsortingng(fieldName:FieldName) -> Ssortingng { switch fieldName { case .CITY: return "city" case .LATITUDE: return "latitude" case .LONGITUDE: return "longitude" case .NAME: return "name" case .GRADE: return "overallGrade" case .POSTAL_CODE: return "postalCode" case .STATE: return "state" case .REVIEW_COUNT: return "reviewCount" case .COORDINATES: return "coordinates" } } } 

À partir de Swift, vous pouvez utiliser .ssortingng sur une énumération (similaire à .rawValue ). Depuis Objective-C, vous pouvez utiliser [ServiceProvider FieldNameToSsortingng:enumValue];

Vous pouvez créer une liste Inner privée. L’implémentation est un peu répétable, mais claire et facile. 1 ligne rawValue , 2 lignes init , qui se ressemblent toujours. L’ Inner dispose d’une méthode renvoyant l’équivalent “externe”, et inversement.

A l’avantage supplémentaire que vous pouvez directement mapper le cas d’énumération à une Ssortingng , contrairement aux autres réponses ici.

S’il vous plaît n’hésitez pas à tirer parti de cette réponse si vous savez comment résoudre le problème de répétabilité avec les modèles, je n’ai pas le temps de me mêler à cela dès maintenant.

 @objc enum MyEnum: NSInteger, RawRepresentable, Equatable { case option1, option2, option3 // MARK: RawRepresentable var rawValue: Ssortingng { return toInner().rawValue } init?(rawValue: Ssortingng) { guard let value = Inner(rawValue: rawValue)?.toOuter() else { return nil } self = value } // MARK: Obj-C support private func toInner() -> Inner { switch self { case .option1: return .option1 case .option3: return .option3 case .option2: return .option2 } } private enum Inner: Ssortingng { case option1 = "option_1", option2 = "option_2", option3 = "option_3" func toOuter() -> MyEnum { switch self { case .option1: return .option1 case .option3: return .option3 case .option2: return .option2 } } } } 

J’ai eu un cas d’utilisation où je devais toujours associer une valeur de chaîne du côté Swift. J’ai écrit à propos de ma solution ici: https://medium.com/@oscarcortes/using-swift-ssortingng-enums-in-objective-c-f6683da5b92e Essentiellement, vous pouvez append une méthode dans l’énumération Swift qui renvoie une chaîne basée sur la valeur enum actuelle.

Ceci est mon cas d’utilisation:

  • J’évite les chaînes codées en dur à chaque fois que je le peux, de façon à obtenir des avertissements de compilation lorsque je change quelque chose
  • J’ai une liste fixe de valeurs Ssortingng provenant d’un back-end, qui peut aussi être nulle

Voici ma solution qui n’implique aucune chaîne de caractères, prend en charge les valeurs manquantes et peut être utilisée avec élégance dans Swift et Obj-C:

 @objc enum InventoryItemType: Int { private enum SsortingngInventoryItemType: Ssortingng { case vial case syringe case crystalloid case bloodProduct case supplies } case vial case syringe case crystalloid case bloodProduct case supplies case unknown static func fromSsortingng(_ ssortingng: Ssortingng?) -> InventoryItemType { guard let ssortingng = ssortingng else { return .unknown } guard let ssortingngType = SsortingngInventoryItemType(rawValue: ssortingng) else { return .unknown } switch ssortingngType { case .vial: return .vial case .syringe: return .syringe case .crystalloid: return .crystalloid case .bloodProduct: return .bloodProduct case .supplies: return .supplies } } var ssortingngValue: Ssortingng? { switch self { case .vial: return SsortingngInventoryItemType.vial.rawValue case .syringe: return SsortingngInventoryItemType.syringe.rawValue case .crystalloid: return SsortingngInventoryItemType.crystalloid.rawValue case .bloodProduct: return SsortingngInventoryItemType.bloodProduct.rawValue case .supplies: return SsortingngInventoryItemType.supplies.rawValue case .unknown: return nil } } }