Comment rendre une chaîne de caractères SWIFT enum disponible dans Objective-C?
j'ai cette enum String
valeurs, qui seront utilisées pour indiquer à une méthode API qui se connecte à un serveur quel type de server un message a. J'utilise Swift 1.2, donc les énums peuvent être mappés à L'objectif-C
@objc enum LogSeverity : String {
case Debug = "DEBUG"
case Info = "INFO"
case Warn = "WARN"
case Error = "ERROR"
}
j'ai l'erreur
@objc enum crue de type String n'est pas un entier de type
Je n'ai pas réussi à trouver n'importe où qui dit que seuls les entiers peuvent être traduits à L'Objectif-C de Swift. Est-ce le cas? Si oui, n' quelqu'un a-t-il une suggestion de meilleure pratique sur la façon de rendre disponible quelque chose comme ça dans L'objectif-C?
10 réponses
Xcode 6.3 notes de mise à jour (non souligné dans l'original):
Améliorations De La Langue Swift
...
Les énums Swift peuvent maintenant être exportés vers L'Objectif-C en utilisant le @objc attribut. @objc enums doit déclarer un type brut entier, et ne peut pas être utiliser des valeurs génériques ou associées. Parce que Objective-C les énumérations ne sont pas les cas d'enum placés sous leur nom sont importés dans L'Objectif - C en tant que concaténation du nom enum et en cas de nom.
une des solutions est d'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 cet enum 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 = String
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() -> String {
switch self {
case .Wifi: return "wifi"
case .Mobile: return "mobile"
case .Ethernet: return "ethernet"
case .Off: return "off"
}
}
}
Voici contourner si vous voulez vraiment atteindre l'objectif. Cependant, vous pouvez accéder aux valeurs enum dans les objets que L'objectif c accepte, et non pas en tant que valeurs enum réelles.
enum LogSeverity : String {
case Debug = "DEBUG"
case Info = "INFO"
case Warn = "WARN"
case Error = "ERROR"
private func string() -> String {
return self.rawValue
}
}
@objc
class LogSeverityBridge: NSObject {
class func Debug() -> NSString {
return LogSeverity.Debug.string()
}
class func Info() -> NSString {
return LogSeverity.Info.string()
}
class func Warn() -> NSString {
return LogSeverity.Warn.string()
}
class func Error() -> NSString {
return LogSeverity.Error.string()
}
}
l'appel De :
NSString *debugRawValue = [LogSeverityBridge Debug]
Code pour Xcode 8, en utilisant le fait que Int
fonctionne mais d'autres méthodes ne sont pas exposées à L'objectif-C. C'est assez horrible en l'état...
class EnumSupport : NSObject {
class func textFor(logSeverity severity: LogSeverity) -> String {
return severity.text()
}
}
@objc public enum LogSeverity: Int {
case Debug
case Info
case Warn
case Error
func text() -> String {
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 le NS_TYPED_ENUM
macro pour importer les constantes dans Swift.
Par exemple:
.h fichier
typedef NSString *const ProgrammingLanguage NS_TYPED_ENUM;
FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageSwift;
FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageObjectiveC;
.m le fichier
ProgrammingLanguage ProgrammingLanguageSwift = "Swift";
ProgrammingLanguage ProgrammingLanguageObjectiveC = "ObjectiveC";
dans Swift, ceci est importé comme un struct
en tant que tel:
struct ProgrammingLanguage: RawRepresentable, Equatable, Hashable {
typealias RawValue = String
init(rawValue: RawValue)
var rawValue: RawValue { get }
static var swift: ProgrammingLanguage { get }
static var objectiveC: ProgrammingLanguage { get }
}
bien que le type ne soit pas unenum
, il se sent très similaire à un lors de son utilisation en code Swift.
Vous pouvez en lire plus à propos de cette technique dans le "Interaging with capis" de la utilisation de Swift avec la documentation sur le cacao et L'objectif-c
Voici ce que j'ai trouvé. Dans mon cas, cet enum était dans le contexte de fournir 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 string: String {
return ServiceProvider.FieldNameToString(self)
}
}
class func FieldNameToString(fieldName:FieldName) -> String {
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 .string
sur un enum (similaire à .rawValue
).
De Objectif-C, vous pouvez utiliser [ServiceProvider FieldNameToString:enumValue];
Vous pouvez créer un privé Inner
enum. La mise en œuvre est un peu reproductible, mais clair et facile. 1 ligne init, qui se ressemblent toujours. Inner
a une méthode retournant l'équivalent "extérieur", et vice-versa.
A l'avantage supplémentaire que vous pouvez mapper directement l'enum cas d'un String
, contrairement aux autres réponses ici.
n'hésitez à construire sur cette réponse si vous savez comment résoudre le problème de répétabilité avec des modèles, Je n'ai pas de temps pour se mêler avec elle dès maintenant.
@objc enum MyEnum: NSInteger, RawRepresentable, Equatable {
case
option1,
option2,
option3
// MARK: RawRepresentable
var rawValue: String {
return toInner().rawValue
}
init?(rawValue: String) {
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: String {
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ù j'avais encore besoin d'associer une valeur de chaîne dans le côté Swift. J'ai écrit sur ma solution ici: https://medium.com/@oscarcortes/using-swift-string-enums-in-objective-c-f6683da5b92e Essentiellement, vous pouvez ajouter une méthode dans L'enum Swift qui retourne une chaîne basée sur la valeur actuelle de l'enum.
C'est mon cas d'utilisation:
- j'évite les chaînes de caractères codées dur chaque fois que je peux, de sorte que je reçois des avertissements de compilation quand je change quelque chose
- j'ai une liste fixe de la Chaîne de valeurs provenant d'un back-end, qui peut aussi être nul
voici ma solution qui n'implique pas de chaînes codées en dur du tout, supporte les valeurs manquantes, et peut être utilisé avec élégance dans Swift et Obj-C:
@objc enum InventoryItemType: Int {
private enum StringInventoryItemType: String {
case vial
case syringe
case crystalloid
case bloodProduct
case supplies
}
case vial
case syringe
case crystalloid
case bloodProduct
case supplies
case unknown
static func fromString(_ string: String?) -> InventoryItemType {
guard let string = string else {
return .unknown
}
guard let stringType = StringInventoryItemType(rawValue: string) else {
return .unknown
}
switch stringType {
case .vial:
return .vial
case .syringe:
return .syringe
case .crystalloid:
return .crystalloid
case .bloodProduct:
return .bloodProduct
case .supplies:
return .supplies
}
}
var stringValue: String? {
switch self {
case .vial:
return StringInventoryItemType.vial.rawValue
case .syringe:
return StringInventoryItemType.syringe.rawValue
case .crystalloid:
return StringInventoryItemType.crystalloid.rawValue
case .bloodProduct:
return StringInventoryItemType.bloodProduct.rawValue
case .supplies:
return StringInventoryItemType.supplies.rawValue
case .unknown:
return nil
}
}
}