example - swift alamofire headers
Patrón de Singleton y uso adecuado de URLRequestConvertible de Alamofire (1)
Estas son algunas preguntas realmente buenas. Déjame intentar responder a cada uno a su vez.
¿Creo un enrutador de enumeración que implemente URLRequestConvertible para cada modelo en mi capa de modelo?
Esta es una gran pregunta y desafortunadamente no hay una respuesta perfecta. Ciertamente, hay algunas formas en que podría extender el patrón de Router
para acomodar múltiples tipos de objetos. La primera opción sería agregar más casos para admitir otro tipo de objeto. Sin embargo, esto se vuelve peludo rápidamente cuando se obtienen más de 6 o 7 casos. Sus instrucciones de cambio solo comienzan a salirse de control. Por lo tanto, no recomendaría este enfoque.
Otra forma de abordar el problema es mediante la introducción de genéricos en el Router
.
Protocolo RouterObject
protocol RouterObject {
func createObjectPath() -> String
func readObjectPath(identifier: String) -> String
func updateObjectPath(identifier: String) -> String
func destroyObjectPath(identifier: String) -> String
}
Objetos modelo
struct User: RouterObject {
let rootPath = "/users"
func createObjectPath() -> String { return rootPath }
func readObjectPath(identifier: String) -> String { return "/(rootPath)//(identifier)" }
func updateObjectPath(identifier: String) -> String { return "/(rootPath)//(identifier)" }
func destroyObjectPath(identifier: String) -> String { return "/(rootPath)//(identifier)" }
}
struct Company: RouterObject {
let rootPath = "/companies"
func createObjectPath() -> String { return rootPath }
func readObjectPath(identifier: String) -> String { return "/(rootPath)//(identifier)" }
func updateObjectPath(identifier: String) -> String { return "/(rootPath)//(identifier)" }
func destroyObjectPath(identifier: String) -> String { return "/(rootPath)//(identifier)" }
}
struct Location: RouterObject {
let rootPath = "/locations"
func createObjectPath() -> String { return rootPath }
func readObjectPath(identifier: String) -> String { return "/(rootPath)//(identifier)" }
func updateObjectPath(identifier: String) -> String { return "/(rootPath)//(identifier)" }
func destroyObjectPath(identifier: String) -> String { return "/(rootPath)//(identifier)" }
}
Enrutador
let baseURLString = "http://example.com"
var OAuthToken: String?
enum Router<T where T: RouterObject>: URLRequestConvertible {
case CreateObject(T, [String: AnyObject])
case ReadObject(T, String)
case UpdateObject(T, String, [String: AnyObject])
case DestroyObject(T, String)
var method: Alamofire.Method {
switch self {
case .CreateObject:
return .POST
case .ReadObject:
return .GET
case .UpdateObject:
return .PUT
case .DestroyObject:
return .DELETE
}
}
var path: String {
switch self {
case .CreateObject(let object, _):
return object.createObjectPath()
case .ReadObject(let object, let identifier):
return object.readObjectPath(identifier)
case .UpdateObject(let object, let identifier, _):
return object.updateObjectPath(identifier)
case .DestroyObject(let object, let identifier):
return object.destroyObjectPath(identifier)
}
}
// MARK: URLRequestConvertible
var URLRequest: NSMutableURLRequest {
let URL = NSURL(string: baseURLString)!
let mutableURLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(path))
mutableURLRequest.HTTPMethod = method.rawValue
if let token = OAuthToken {
mutableURLRequest.setValue("Bearer /(token)", forHTTPHeaderField: "Authorization")
}
switch self {
case .CreateObject(_, let parameters):
return Alamofire.ParameterEncoding.JSON.encode(mutableURLRequest, parameters: parameters).0
case .UpdateObject(_, _, let parameters):
return Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: parameters).0
default:
return mutableURLRequest
}
}
}
Ejemplo de uso
func exampleUsage() {
let URLRequest = Router.CreateObject(Location(), ["address": "1234 Road of Awesomeness"]).URLRequest
Alamofire.request(URLRequest)
.response { request, response, data, error in
print(request)
print(response)
print(data)
print(error)
}
}
Ahora hay algunas compensaciones que tienes que hacer aquí. En primer lugar, los objetos de su modelo deben cumplir con el protocolo RouterObject
. De lo contrario, el Router
no tiene idea de qué usar para la ruta. Además, deberá asegurarse de que todas sus rutas se puedan construir con un solo identifier
. Si no pueden, este diseño podría no funcionar. El último problema es que no puede almacenar la baseURL
o el OAuthToken
directamente dentro de la enumeración del Router
. Desafortunadamente, las propiedades estáticas y almacenadas todavía no son compatibles en las enumeraciones genéricas.
En cualquier caso, esta sería una forma válida de evitar tener que crear un Router
para cada objeto modelo.
¿
Alamofire.Manager.sharedInstance
usarseAlamofire.Manager.sharedInstance
como mi instancia deNetworkManager
singleton?
Ciertamente podría ser utilizado de esa manera. Realmente depende de su caso de uso y de cómo haya diseñado su acceso a la red. También depende de cuántos tipos diferentes de sesiones necesites. Si necesita sesiones en segundo plano y sesiones predeterminadas, es probable que aún necesite el concepto de un NetworkManager
que contenga cada instancia de Manager
personalizada. Sin embargo, si está llegando a la red con una sesión predeterminada, probablemente la sharedInstance
sea suficiente.
¿Cómo podría
baseURL
labaseURL
delAlamofire
singleton junto con el patrónRouter
?
Buena pregunta ... el siguiente código es un ejemplo de cómo se podría hacer.
Extensión de Alamofire Manager
extension Manager {
static let baseURLString = "http://example.com"
static var OAuthToken: String?
}
Router URLRequestConvertible Actualizaciones
var URLRequest: NSMutableURLRequest {
let URL = NSURL(string: Alamofire.Manager.baseURLString)!
let mutableURLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(path))
mutableURLRequest.HTTPMethod = method.rawValue
if let token = Alamofire.Manager.OAuthToken {
mutableURLRequest.setValue("Bearer /(token)", forHTTPHeaderField: "Authorization")
}
switch self {
case .CreateObject(_, let parameters):
return Alamofire.ParameterEncoding.JSON.encode(mutableURLRequest, parameters: parameters).0
case .UpdateObject(_, _, let parameters):
return Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: parameters).0
default:
return mutableURLRequest
}
}
Esperemos que eso ayude a arrojar algo de luz. ¡La mejor de las suertes!
Esta es una pregunta de 2 partes, la primera es similar a esta pregunta aquí: Uso correcto de URLRequestConvertible de Alamofire . ¡Pero necesito un poco más de ayuda!
1) ¿Creo un enrutador de enumeración que implemente URLRequestConvertible para cada modelo en mi capa de modelo?
La página de github de alamofire proporciona un ejemplo de un enrutador que he copiado aquí:
enum Router: URLRequestConvertible {
static let baseURLString = "http://example.com"
static var OAuthToken: String?
case CreateUser([String: AnyObject])
case ReadUser(String)
case UpdateUser(String, [String: AnyObject])
case DestroyUser(String)
var method: Alamofire.Method {
switch self {
case .CreateUser:
return .POST
case .ReadUser:
return .GET
case .UpdateUser:
return .PUT
case .DestroyUser:
return .DELETE
}
}
var path: String {
switch self {
case .CreateUser:
return "/users"
case .ReadUser(let username):
return "/users//(username)"
case .UpdateUser(let username, _):
return "/users//(username)"
case .DestroyUser(let username):
return "/users//(username)"
}
}
// MARK: URLRequestConvertible
var URLRequest: NSURLRequest {
let URL = NSURL(string: Router.baseURLString)!
let mutableURLRequest = NSMutableURLRequest(URL: URL.URLByAppendingPathComponent(path))
mutableURLRequest.HTTPMethod = method.rawValue
if let token = Router.OAuthToken {
mutableURLRequest.setValue("Bearer /(token)", forHTTPHeaderField: "Authorization")
}
switch self {
case .CreateUser(let parameters):
return Alamofire.ParameterEncoding.JSON.encode(mutableURLRequest, parameters: parameters).0
case .UpdateUser(_, let parameters):
return Alamofire.ParameterEncoding.URL.encode(mutableURLRequest, parameters: parameters).0
default:
return mutableURLRequest
}
}
}
Cuando miro esto (soy nuevo en swift, por favor tenga paciencia conmigo> _ <) Veo operaciones en un objeto de usuario; están creando un usuario, actualizando un usuario, etc. Entonces, si tuviera una persona, empresa, ubicación de objetos modelo en mi capa de modelo, ¿crearía un enrutador para cada objeto modelo?
2) Cuando interactúo en gran medida con una API, estoy acostumbrado a crear un singleton de "administrador de red" para abstraer la capa de red y mantener los encabezados y la baseurl para esa API. El alamofire tiene un "administrador" descrito aquí:
Los métodos de conveniencia de nivel superior como Alamofire.request utilizan una instancia compartida de Alamofire.Manager, que está configurada con la configuración predeterminada de NSURLSessionConfiguration. Como tal, las siguientes dos afirmaciones son equivalentes:
Alamofire.request(.GET, "http://httpbin.org/get")
let manager = Alamofire.Manager.sharedInstance
manager.request(NSURLRequest(URL: NSURL(string: "http://httpbin.org/get")))
¿Es este administrador lo que debería usar como mi singleton? Si es así, ¿cómo configuro la baseurl en el administrador? Además, si uso este administrador, ¿esto puede / puede funcionar junto con la construcción del enrutador que se muestra arriba (con cada configuración de objeto modelo es baseurl y NSURLRquest)? Si es así, ¿puedes dar un ejemplo simple?
Soy nuevo en la biblioteca de Alamofire y rápido. Entonces, sé que hay muchos agujeros en mi comprensión, ¡pero solo estoy tratando de entender lo mejor que puedo! Cualquier información ayuda. Gracias.