はじめに
SwiftのEnumにはObjective-Cのときにはなかった特徴があります。
- Function や Computed Property が持てる。
- 関連値が持てる。
- プロトコルが使える。
- ジェネリクスが使える。
どんな使い方があるか、Cocoapodsの有名ライブラリを見てみました。
成功/失敗
成功と失敗の状態をEnumで表しつつ、失敗の方にはエラーオブジェクトを関連値として渡す。
Alamofire/Validation.swift at 990fded98afe5135dc418e1f6eb0287027dd067f · Alamofire/Alamofire
public enum ValidationResult {
case Success
case Failure(NSError)
}
ErrorTypeプロトコルとの組み合わせ
throw
で投げられるエラーをEnumで定義する場合は、ErrorTypeプロトコルを付ける。
realm-cocoa/Error.swift at 7d97479d49ea896859eb3b32d5caf18b5ce1b9ba · realm/realm-cocoa
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
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が多いですね...。
他にも見つけたら適宜追加しようと思います。