programing

목표-C에서 스위프트 스트링 열거를 사용할 수 있도록 하는 방법?

css3 2023. 10. 22. 20:17

목표-C에서 스위프트 스트링 열거를 사용할 수 있도록 하는 방법?

나는 이 열거를 가지고 있습니다.Stringvalues - 서버에 로그를 기록하는 API 메서드에 메시지의 서버 유형을 지정하는 데 사용됩니다.저는 스위프트 1.2를 사용하고 있기 때문에 enum을 Objective-C에 매핑할 수 있습니다.

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

오류가 납니다.

@objc 열거 원시 유형 문자열이 정수 유형이 아닙니다.

스위프트에서 Objective-C로 정수만 번역할 수 있다는 곳을 찾지 못했습니다.이런 경우입니까?그렇다면 Objective-C에서 이와 같은 것을 사용할 수 있도록 하는 방법에 대한 모범 사례 제안이 있는 사람이 있습니까?

해결책 중 하나는 다음을 사용하는 것입니다.RawRepresentable의전의

init 메서드와 rawValue 메서드를 쓰는 것이 이상적이지는 않지만 Swift 및 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:
                return nil
        }
    }
}

Xcode 6.3 릴리즈 노트(강조사항 추가)에서 다음을(를)

빠른 언어 향상

...
이제 @objc 특성을 사용하여 스위프트 엔움을 Objective-C로 내보낼 수 있습니다.@objcenums는 정수 원시 유형을 선언해야 하며, 일반적이거나 관련 값을 사용할 수 없습니다.Objective-Cenums는 namespatched가 아니기 때문에 열거형 사례는 열거형 이름과 사례 이름의 연결로 Objective-C로 가져옵니다.

여기에 효과적인 해결책이 있습니다.

@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"
        }
    }
}

정말로 목표를 달성하고 싶다면 여기에 해결 방법이 있습니다.그러나 실제 열거값이 아니라 Objective C가 허용하는 개체의 열거값에 액세스할 수 있습니다.

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()
    }
}

전화할 내용:

NSString *debugRawValue = [LogSeverityBridge Debug]

것이 (Objective) C 을 .NS_TYPED_ENUMmacro에서 Swift의 상수를 가져옵니다.

예를 들어,

.h 파일

typedef NSString *const ProgrammingLanguage NS_TYPED_ENUM;

FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageSwift;
FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageObjectiveC;

.m파일

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

스위프트에서 이것은 다음과 같이 수입됩니다.struct다음과 같은 경우:

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 }
}

유형이 다음과 같이 브리지되지는 않지만enum, 스위프트 코드로 사용했을 때와 매우 유사한 느낌이 듭니다.

기법에 대한 자세한 내용은 관련 목표-C 상수 그룹화에서 확인할 수 있습니다.

Xcode 8이라는 Int작동하지만 다른 방법은 Objective-C에 노출되지 않습니다.지금 상태로는 꽤나 끔찍한데요...

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"
        }
    }
}

사용 사례는 다음과 같습니다.

  • 가능할 때마다 하드 코딩된 문자열을 사용하지 않으므로 변경할 때 컴파일 경고가 표시됩니다.
  • 백엔드에서 오는 String 값의 고정된 목록이 있습니다. 이 목록은 0일 수도 있습니다.

하드 코딩된 Strings가 전혀 포함되지 않고 누락된 값을 지원하며 Swift와 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
        }
    }
}

이것이 제가 생각해낸 것입니다.제 경우 이 열거는 특정 클래스에 대한 정보를 제공하는 상황에 있었습니다.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"
        }
    }
}

스위프트에서 사용할 수 있습니다..string(와 유사한) 열거적으로.rawValue). Objective-C 에서 사용할 수 있습니다.[ServiceProvider FieldNameToString:enumValue];

개인 정보를 생성할 수 있습니다.Innerenum. 구현은 약간 반복 가능하지만 명확하고 쉽습니다. 1줄rawValue, 2줄init, 항상 똑같아 보이잖아요. 그.Inner는 "outer" 등가를 반환하는 방법을 가지고 있으며, 그 반대의 경우에는 versa을 반환합니다.

열거형 사례를 에 직접 매핑할 수 있는 추가 이점이 있습니다.String, 다른 대답들과는 다르게.

템플릿으로 반복성 문제를 해결할 수 있는 방법을 알고 계시다면 이 답변을 기꺼이 작성해 주시기 바랍니다. 지금은 제가 그것과 어울릴 시간이 없습니다.

@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
            }
        }
    }
}

제 생각에 @Remi의 답변은 제가 했던 것처럼 어떤 상황에 따라 저는 이렇게 생각합니다.

오류는 스크린샷입니다. 그래서 나는 @Remi의 답변을 위해 내 판을 올립니다.

@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:
                return nil
        }
    }
}

언급URL : https://stackoverflow.com/questions/30480338/how-to-make-a-swift-string-enum-available-in-objective-c