In Swift type system, [Child]
and [Parent]
aren't equal because Swift's generics doesn't support covariance. You can use overload with generics type constraint instead subtype polymorphism and dynamic type casting.
First, create three overloads of handleResponse()
methods same as myRequest〜
methods:
func handleResponse(alamofireReponse: AlamofireReponse<AnyObject, NSError>, completionHandler: (MyResponse<AnyObject> -> Void)) {
switch alamofireReponse {
case .Success(let data):
completionHandler(.Success(data))
case .Failure(let error):
completionHandler(.Failure(error))
}
}
func handleResponse<T: Mappable where T: Object>(alamofireReponse: AlamofireReponse<T, NSError>, completionHandler: (MyResponse<T> -> Void)) {
switch alamofireReponse {
case .Success(let data):
add(data)
completionHandler(.Success(data))
case .Failure(let error):
completionHandler(.Failure(error))
}
}
func handleResponse<T: Mappable where T: Object>(alamofireReponse: AlamofireReponse<[T], NSError>, completionHandler: (MyResponse<[T]> -> Void)) {
switch alamofireReponse {
case .Success(let data):
add(data)
completionHandler(.Success(data))
case .Failure(let error):
completionHandler(.Failure(error))
}
}
Then, change type constraints of myRequest〜
methods to satisfy the constraints of each handleResponse
methods.
func myRequestObject<T: Mappable where T: Object>(completionHandler: (MyResponse<T> -> Void)) {
responseObject { alamofireReponse in
handleResponse(alamofireReponse, completionHandler: completionHandler)
}
}
func myRequestArray<T: Mappable where T: Object>(completionHandler: (MyResponse<[T]> -> Void)) {
responseArray { alamofireReponse in
handleResponse(alamofireReponse, completionHandler: completionHandler)
}
}
By doing this, handleResponse ()
method and add ()
method will be dispatched to the appropriate method at compile time depending on the type of argument. You do not need to check the type dynamically.
The entire code is below, just in case:
import Foundation
// Alamofire
enum AlamofireReponse<T, E> {
case Success(T)
case Failure(E)
}
func responseJSON(alamofireReponse: AlamofireReponse<AnyObject, NSError> -> Void) {
alamofireReponse(.Success([["type": "not_object"], ["type": "not_object"]]))
}
// ObjectMapper
protocol Mappable {
init()
}
// AlamofireObjectMapper
func responseObject<T: Mappable>(alamofireReponse: AlamofireReponse<T, NSError> -> Void) {
alamofireReponse(.Success(T()))
}
func responseArray<T: Mappable>(alamofireReponse: AlamofireReponse<[T], NSError> -> Void) {
alamofireReponse(.Success([T(), T()]))
}
// RealmSwift
class Object {}
func add(object: Object) {
print("adding single object works") // This line would run
}
func add<T: SequenceType where T.Generator.Element: Object>(objects: T) {
print("adding multiple objects works") // This line would not
}
// My code
final class Post: Object, Mappable {}
final class Comment: Object, Mappable {}
enum MyResponse<T> {
case Success(T)
case Failure(NSError)
}
func myRequestJSON(completionHandler: (MyResponse<AnyObject> -> Void)) {
responseJSON { alamofireReponse in
handleResponse(alamofireReponse, completionHandler: completionHandler)
}
}
func myRequestObject<T: Mappable where T: Object>(completionHandler: (MyResponse<T> -> Void)) {
responseObject { alamofireReponse in
handleResponse(alamofireReponse, completionHandler: completionHandler)
}
}
func myRequestArray<T: Mappable where T: Object>(completionHandler: (MyResponse<[T]> -> Void)) {
responseArray { alamofireReponse in
handleResponse(alamofireReponse, completionHandler: completionHandler)
}
}
func handleResponse(alamofireReponse: AlamofireReponse<AnyObject, NSError>, completionHandler: (MyResponse<AnyObject> -> Void)) {
switch alamofireReponse {
case .Success(let data):
completionHandler(.Success(data))
case .Failure(let error):
completionHandler(.Failure(error))
}
}
func handleResponse<T: Mappable where T: Object>(alamofireReponse: AlamofireReponse<T, NSError>, completionHandler: (MyResponse<T> -> Void)) {
switch alamofireReponse {
case .Success(let data):
add(data)
completionHandler(.Success(data))
case .Failure(let error):
completionHandler(.Failure(error))
}
}
func handleResponse<T: Mappable where T: Object>(alamofireReponse: AlamofireReponse<[T], NSError>, completionHandler: (MyResponse<[T]> -> Void)) {
switch alamofireReponse {
case .Success(let data):
add(data)
completionHandler(.Success(data))
case .Failure(let error):
completionHandler(.Failure(error))
}
}
// Usage
myRequestJSON { response in
}
myRequestObject { (response: MyResponse<Post>) in
}
myRequestArray { (response: MyResponse<[Post]>) in
}