我正在开发一个涉及Alamofire,ObjectMapper和RealmSwift的Swift项目,遇到一种情况,我必须检查泛型类型的对象是否是Realm Object
的数组。
我的问题是:如何检查泛型类型的对象是否是Swift中某个类型子类型的数组?
冗长的版本:我制作了一个我的问题的最小工作示例。请参阅我的gist here。 您可以将其复制到Xcode Playground,并看到第31行运行而第35行没有。
我能够通过更改70&线来使其工作。 71
这
if let array = data as? [Object] {
add(array)
}
到
if let array = data as? NSArray where array.count > 0 && array[0] is Object {
add(array as! [Object])
}
但是这个解决方案甚至还不完美,因为它必须涉及Foundation
。我更喜欢“纯粹的”斯威夫特。
<script src="https://gist.github.com/T-Pham/44fe5b7c3a669db34d856b54e15f278a.js"></script>
已移除:短版本无法完全代表实际问题。
简短版本:
protocol Protocol {
init()
}
class Parent {}
final class Child1: Parent, Protocol {}
final class Child2: Parent, Protocol {}
func foo<T: Protocol>(array: [T]) {
if array is [Parent] { // This won't compile
}
}
foo([Child1(), Child1()])
答案 0 :(得分:0)
在Swift类型系统中,[Child]
和[Parent]
并不相同,因为Swift的泛型并不支持协方差。您可以使用泛型类型约束重载,而不是子类型多态和动态类型转换。
首先,创建与handleResponse()
方法相同的myRequest〜
方法的三个重载:
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))
}
}
然后,更改myRequest〜
方法的类型约束以满足每个handleResponse
方法的约束。
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)
}
}
通过执行此操作,handleResponse ()
方法和add ()
方法将在编译时分配给适当的方法,具体取决于参数的类型。您无需动态检查类型。
整个代码如下:以防万一:
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
}