LoginSignup
21
20

More than 5 years have passed since last update.

【Swift】Enumの実際の使われ方を調べてみた

Posted at

はじめに

SwiftのEnumにはObjective-Cのときにはなかった特徴があります。

  • Function や Computed Property が持てる。
  • 関連値が持てる。
  • プロトコルが使える。
  • ジェネリクスが使える。

どんな使い方があるか、Cocoapodsの有名ライブラリを見てみました。

成功/失敗

成功と失敗の状態をEnumで表しつつ、失敗の方にはエラーオブジェクトを関連値として渡す。

Alamofire/Validation.swift at 990fded98afe5135dc418e1f6eb0287027dd067f · Alamofire/Alamofire

Validation.swift
    public enum ValidationResult {
        case Success
        case Failure(NSError)
    }

ErrorTypeプロトコルとの組み合わせ

throwで投げられるエラーをEnumで定義する場合は、ErrorTypeプロトコルを付ける。

realm-cocoa/Error.swift at 7d97479d49ea896859eb3b32d5caf18b5ce1b9ba · realm/realm-cocoa

Error.swift
public enum Error: ErrorType {

    ...

    /// Error thrown by Realm if no other specific error is returned when a realm is opened.
    case Fail

    /// Error thrown by Realm for any I/O related exception scenarios when a realm is opened.
    case FileAccess

    /// Error thrown by Realm if the user does not have permission to open or create
    /// the specified file in the specified access mode when the realm is opened.
    case FilePermissionDenied

    /// Error thrown by Realm if the file already exists when a copy should be written.
    case FileExists

    /// Error thrown by Realm if no file was found when a realm was opened as
    /// read-only or if the directory part of the specified path was not found
    /// when a copy should be written.
    case FileNotFound

    /// Error thrown by Realm if the database file is currently open in another process which
    /// cannot share with the current process due to an architecture mismatch.
    case IncompatibleLockFile

    /// Returned by RLMRealm if a file format upgrade is required to open the file,
    /// but upgrades were explicilty disabled.
    case FileFormatUpgradeRequired
}

成功/失敗 + ジェネリクス

成功と失敗の状態をEnumで定義し、関連値の型をジェネリクスで指定する。
下のAlamofireの例では、前項目のErrorTypeプロトコルも使用している。

Alamofire/Result.swift at 990fded98afe5135dc418e1f6eb0287027dd067f · Alamofire/Alamofire

Result.swift
public enum Result<Value, Error: ErrorType> {
    case Success(Value)
    case Failure(Error)

    ...
}

Function/Computed Property

自身がどのEnum値かによって返す値を変える。
ただ、あまり分岐が複雑になるようであれば、プロトコル+構造体にした方がコードを分離できて良さそう。

Alamofire/ParameterEncoding.swift at 990fded98afe5135dc418e1f6eb0287027dd067f · Alamofire/Alamofire

public enum ParameterEncoding {
    case URL
    case URLEncodedInURL
    case JSON
    case PropertyList(NSPropertyListFormat, NSPropertyListWriteOptions)
    case Custom((URLRequestConvertible, [String: AnyObject]?) -> (NSMutableURLRequest, NSError?))

    /**
        Creates a URL request by encoding parameters and applying them onto an existing request.
        - parameter URLRequest: The request to have parameters applied
        - parameter parameters: The parameters to apply
        - returns: A tuple containing the constructed request and the error that occurred during parameter encoding, 
                   if any.
    */
    public func encode(
        URLRequest: URLRequestConvertible,
        parameters: [String: AnyObject]?)
        -> (NSMutableURLRequest, NSError?)
    {
        var mutableURLRequest = URLRequest.URLRequest

        guard let parameters = parameters where !parameters.isEmpty else {
            return (mutableURLRequest, nil)
        }

        var encodingError: NSError? = nil

        switch self {
        case .URL, .URLEncodedInURL:
            func query(parameters: [String: AnyObject]) -> String {
                var components: [(String, String)] = []

                for key in parameters.keys.sort(<) {
                    let value = parameters[key]!
                    components += queryComponents(key, value)
                }

                return (components.map { "\($0)=\($1)" } as [String]).joinWithSeparator("&")
            }

            func encodesParametersInURL(method: Method) -> Bool {
                switch self {
                case .URLEncodedInURL:
                    return true
                default:
                    break
                }

                switch method {
                case .GET, .HEAD, .DELETE:
                    return true
                default:
                    return false
                }
            }

            if let method = Method(rawValue: mutableURLRequest.HTTPMethod) where encodesParametersInURL(method) {
                if let URLComponents = NSURLComponents(URL: mutableURLRequest.URL!, resolvingAgainstBaseURL: false) {
                    let percentEncodedQuery = (URLComponents.percentEncodedQuery.map { $0 + "&" } ?? "") + query(parameters)
                    URLComponents.percentEncodedQuery = percentEncodedQuery
                    mutableURLRequest.URL = URLComponents.URL
                }
            } else {
                if mutableURLRequest.valueForHTTPHeaderField("Content-Type") == nil {
                    mutableURLRequest.setValue(
                        "application/x-www-form-urlencoded; charset=utf-8",
                        forHTTPHeaderField: "Content-Type"
                    )
                }

                mutableURLRequest.HTTPBody = query(parameters).dataUsingEncoding(
                    NSUTF8StringEncoding,
                    allowLossyConversion: false
                )
            }
        case .JSON:
            do {
                let options = NSJSONWritingOptions()
                let data = try NSJSONSerialization.dataWithJSONObject(parameters, options: options)

                mutableURLRequest.setValue("application/json", forHTTPHeaderField: "Content-Type")
                mutableURLRequest.HTTPBody = data
            } catch {
                encodingError = error as NSError
            }
        case .PropertyList(let format, let options):
            do {
                let data = try NSPropertyListSerialization.dataWithPropertyList(
                    parameters,
                    format: format,
                    options: options
                )
                mutableURLRequest.setValue("application/x-plist", forHTTPHeaderField: "Content-Type")
                mutableURLRequest.HTTPBody = data
            } catch {
                encodingError = error as NSError
            }
        case .Custom(let closure):
            (mutableURLRequest, encodingError) = closure(mutableURLRequest, parameters)
        }

        return (mutableURLRequest, encodingError)
    }

おわりに

とりあえず調べた範囲で挙げてみました。
いくつか見てみたのですが、結局Alamofireが多いですね...。
他にも見つけたら適宜追加しようと思います。

21
20
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
20