How do you use a switch statement with a nested enum?

后端 未结 4 867
你的背包
你的背包 2021-01-31 10:32

I\'ve created an enum for Instagram endpoints with nested enums similar to Moya.

enum Instagram {
    enum Media {
        case Popular
        case Shortcode(id         


        
相关标签:
4条回答
  • 2021-01-31 10:50

    Enum case Search is not a member of type Instagram

    As the compiler say, Search is not a member of type Instagram. It's just an enum in the scope of Instagram. You have to create a member that is an instance of Search in Instagram

    struct Instagram {
        enum Media {
            case Search(lat: Float, lng: Float, distance: Int)
        }
        // something like:
         var media = .Search(lat: 0, lng: 0, distance: 0) 
        // I'm not sure this one is right syntax
        // because I can't check it right now.
        // please just get the idea
    }
    extension Instagram: TargetType {
        var path: String {
            switch self.media {
            case .Search(let _, let _, let _):
                return "/media/search"
            }
        }
    }
    
    0 讨论(0)
  • 2021-01-31 10:53

    By adding an associated value for the nested enum you can access it using a switch statement.

    enum Instagram {
        enum MediaEndpoint {
            case Search(lat: Float, lng: Float, distance: Int)
        }
        case Media(MediaEndpoint)
    }
    
    extension Instagram: TargetType {
        var path: String {
            switch self {
            case .Media(.Search):
                return "/media/search"
            }
        }
    }
    
    // Demo
    
    protocol TargetType {
        var path: String { get }
    }
    
    class MoyaProvider<Target: TargetType> {
        func request(_ target: Target, completion: @escaping () -> ()) {}
    }
    
    let provider = MoyaProvider<Instagram>()
    provider.request(.Media(.Search(lat: 0, lng: 0, distance: 0))) {}
    
    0 讨论(0)
  • 2021-01-31 10:55

    I'm adding a more general answer for a few reasons.

    1. This is the only open question regarding nested enums and switch statements. The other one is sadly closed.
    2. The only legit answer does not show how to assign the value of a nested enum to a symbol. The syntax was not intuitive to me.
    3. None of the other answers have extensive case examples.
    4. An enum nested 3 levels deep is more illustrative of the required syntax. Using efremidze answer still took me a while to work it out.
    
    enum Action {
        case fighter(F)
        case weapon(W)
    
        enum F {
            case attack(A)
            case defend(D)
            case hurt(H)
    
            enum A {
                case fail
                case success
            }
            enum D {
                case fail
                case success
            }
            enum H {
                case none
                case some
            }
        }
        enum W {
            case swing
            case back
        }
    }
    
    // Matches "3 deep"
    let action = Action.fighter(.attack(.fail))
    // Matches "1 deep" because more general case listed first.
    let action2 = Action.weapon(.swing)
    
    switch action {
    case .fighter(.attack(.fail)):
        print("3 deep")
    case .weapon:
        print("1 deep")
    case .weapon(.swing):
        print("2 deep to case")
    case .fighter(.attack):
        print("2 deep to another enum level")
    default:
        print("WTF enum")
    }
    
    0 讨论(0)
  • 2021-01-31 11:01

    There is a couple of problems with your architecture. You should know when and why you need to use extensions and protocols and how you should structure your blocks of code.

    1. If your type needs to conform to that protocol, feel free to use it to ensure you set your own standards. I don't even see that in the github project you referred to.
    2. Extension are good way to have a primitive type and extend its functionality in other parts of the project. It doesn't make sense to me why you should extend the type right after declaration. A good use case of it is where the String type has been extended to support URL Encoded values:
    private extension String {
        var URLEscapedString: String {
            return self.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())!
        }
    }
    
    1. When you are using this type of switch-case block
    switch self {
        case .Zen:
            return "/zen"
        case .UserProfile(let name):
            return "/users/\(name.URLEscapedString)"
        case .UserRepositories(let name):
            return "/users/\(name.URLEscapedString)/repos"
    }
    

    The value in the case should be a member of self. that's why it can not find the type. the type is declared inside Instagram enum but it doesn't hold value in the self. it holds value inside Media. So move your media related function into the declaration of Media and access them there. That way self is referring to Media. Here's the full working code for me:

    
    private extension String {
        var URLEscapedString: String {
            return self.stringByAddingPercentEncodingWithAllowedCharacters(NSCharacterSet.URLHostAllowedCharacterSet())!
        }
    }

    public enum Instagram {

    public enum Media {
        case Search(String)
    
        var path:String {
            switch self {
    
            case Media.Search(let keyword):
                return "/media/search/\(keyword.URLEscapedString)"
            }
        }
    }
    

    }

    var me = Instagram.Media.Search("me") print(me.path)

    1. As a piece of advice, in each step of building your whole architecture just question yourself if that piece of code belongs to that type or should be accessible publicly. In this case it makes complete sense to move search to Media cause you are searching media. You can add the same pattern for something like User and have search under user that returns different value.
    0 讨论(0)
提交回复
热议问题