ProgramingTip

Objective-C에서 Swift String 열거 형을 사용하는 방법은 무엇입니까?

bestdevel 2020. 12. 14. 20:36
반응형

Objective-C에서 Swift String 열거 형을 사용하는 방법은 무엇입니까?


이 열거 형 String값은 서버에 기록하는 API 메소드에 메시지에 어떤 종류의 서버가 있는지 알려주는 데 사용됩니다. Swift 1.2를 사용하고 있으므로 열거 형을 Objective-C에 매핑 할 수 있습니다.

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

오류가 발생합니다.

@objc enum 원시 유형이 아닌 정수 유형이 아닙니다.

정수만 Swift에서 Objective-C로 변환 할 수있는 말하는 곳을 찾을 수 있습니다. 이것이 사실입니까? Objective-C에서 이와 같은 것을 제공하는 방법에 대한 모범 사례 제안이 있습니까?


로부터 엑스 코드 6.3 릴리스 노트 (강조는 추가) :

Swift 언어 향상

...
@objc 속성을 사용하여 Swift 열거 형을 Objective-C로 정렬 할 수 있습니다. @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

    struct Constants {
        static let types: [LogSeverity: String] = [
            .debug: "DEBUG",
            .info: "INFO",
            .warn: "WARN",
            .error: "ERROR"
        ]
    }

    public typealias RawValue = String

    public var rawValue: RawValue {
        guard let value = Constants.routes[self] else {
            fatalError("constants definition is missing: \(self)")
        }
        return value
    }

    public init?(rawValue: RawValue) {
        guard let severity = Constants.types.first(where: { $0.value == rawValue }) else {
            return nil
        }
        self = severity.key
    }
}

작동하는 솔루션이 있습니다.

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

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

(목표) C에서 값을 정의하는 데 신경 쓰지에서, NS_TYPED_ENUM매크로를 사용하여 Swift 상수를 사용할 수 있습니다 .

예를 들면 :

.h 파일

typedef NSString *const ProgrammingLanguage NS_TYPED_ENUM;

FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageSwift;
FOUNDATION_EXPORT ProgrammingLanguage ProgrammingLanguageObjectiveC;

.m 파일

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

Swift에서는 다음과 같이 가져옵니다 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 }
}

유형이 브리지는 아니지만 enumSwift 코드에서 사용할 때 유형 과 매우 유사합니다.

이 기술에 대한 자세한 내용은 Cocoa 및 Objective-C에서 Swift 사용 문서 의 "C API와 상호 작용"에서 확인할 수 있습니다.


이 내 사용 사례입니다.

  • 할 수있을 때마다 하드 코딩 될 때마다 준비를 코딩 할 때 경고를받습니다.
  • 백엔드에서 오는 고정 및 값 목록이 있으며, 이는 nil 일 수도 있습니다.

다음은 하드 코딩 된 코드가 전혀없고 누락 된 값을 지원하며 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"
        }
    }
}

Swift에서 .string열거 형 ()에 사용할 수 있습니다 .rawValue. Objective-C에서 다음을 사용할 수 있습니다.[ServiceProvider FieldNameToString:enumValue];


개인 Inner열거 형을 만들 수 있습니다 . 구현은 약간의 반복 가능하지만 명확하고 신뢰할 수 있습니다. 항상 동일하게 보이는 1 줄 rawValue, 2 줄 init. 에 해당 Inner하는 "외부"를 반환하는 메서드가 해당 반대의 경우도 마찬가지입니다.

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

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

반응형