2015-11-03 39 views
1

让说我下面的代码获取数组类型元素的(通过反射)

class Foo { 
} 

var fooArray : Array<Foo> = Array<Foo>() 
// This is important because in my code I will get Any (vs Array<Foo) 
var fooArrayAny : Any = foo 

我希望能够得到一个类型出可变fooArrayAny的。

如果我有fooArray,我会做这样的事情:

let type = fooArray.dynamicType.Element().dynamicType 

然而,这并不fooArrayAny工作。它说,它没有成员元素()

+0

fooArray.dynamicType.Element()被实例化的Foo,而不会返回一个类型。什么类型的对象是在foo中,你期望从中得到什么? –

+0

@ChrisGulley:我忘了在最后添加dynamicType以获得它的类型 –

回答

2

如果设置NSObject的基类美孚的,那么你可以使用下面的代码:

class EVReflectionTests: XCTestCase {  
    func testArrayInstance() { 
     let fooArray : Array<Foo> = Array<Foo>() 
     let fooArrayAny : Any = fooArray 
     if let arr = fooArray as? Array { 
      let i = arr.getArrayTypeInstance(arr) 
      print("i = \(i)") 
     } 
    } 
} 

class Foo: NSObject { 
} 



extension Array { 
    public func getArrayTypeInstance<T>(arr:Array<T>) -> T { 
     return arr.getTypeInstance() 
    } 

    public func getTypeInstance<T>() -> T { 
     let nsobjectype : NSObject.Type = T.self as! NSObject.Type 
     let nsobject: NSObject = nsobjectype.init() 
     return nsobject as! T 
    } 
} 

该代码的一个片段我库EVReflection

更新:

我注意到,在上面的代码错误。我用fooArray而不是fooArrayAny。当将其更改为fooArrayAny时,我得到与编译器没有该元素相同的错误。玩过这个之后,我发现了一个可行的解决方案。它再次具有我的EVReflection库的部分代码。

class EVReflectionTests: XCTestCase {  
    func testArrayInstance() { 
     let fooArray : Array<Foo> = Array<Foo>() 
     let fooArrayAny : Any = fooArray 

     if let _ = fooArrayAny as? NSArray { 
      var subtype: String = "\(Mirror(reflecting: fooArrayAny))" 
      subtype = subtype.substringFromIndex((subtype.componentsSeparatedByString("<") [0] + "<").endIndex) 
      subtype = subtype.substringToIndex(subtype.endIndex.predecessor()) 
      print("The type of the array elements = \(subtype)") 
      if let instance = swiftClassFromString(subtype) { 
       print("An instance of the array element = \(instance)") 
       let type = instance.dynamicType 
       print("An instance of the array element = \(type)") 
      } 
     } 
    } 

    // All code below is a copy from the EVReflection library. 

    func swiftClassFromString(className: String) -> NSObject? { 
     var result: NSObject? = nil 
     if className == "NSObject" { 
      return NSObject() 
     } 
     if let anyobjectype : AnyObject.Type = swiftClassTypeFromString(className) { 
      if let nsobjectype : NSObject.Type = anyobjectype as? NSObject.Type { 
       let nsobject: NSObject = nsobjectype.init() 
       result = nsobject 
      } 
     } 
     return result 
    } 

    func swiftClassTypeFromString(className: String) -> AnyClass! { 
     if className.hasPrefix("_Tt") { 
      return NSClassFromString(className) 
     } 
     var classStringName = className 
     if className.rangeOfString(".", options: NSStringCompareOptions.CaseInsensitiveSearch) == nil { 
      let appName = getCleanAppName() 
      classStringName = "\(appName).\(className)" 
     } 
     return NSClassFromString(classStringName) 
    } 

    func getCleanAppName(forObject: NSObject? = nil)-> String { 
     var bundle = NSBundle.mainBundle() 
     if forObject != nil { 
      bundle = NSBundle(forClass: forObject!.dynamicType) 
     } 

     var appName = bundle.infoDictionary?["CFBundleName"] as? String ?? "" 
     if appName == "" { 
      if bundle.bundleIdentifier == nil { 
       bundle = NSBundle(forClass: EVReflection().dynamicType) 
      } 
     appName = (bundle.bundleIdentifier!).characters.split(isSeparator: {$0 == "."}).map({ String($0) }).last ?? "" 
     } 
     let cleanAppName = appName 
      .stringByReplacingOccurrencesOfString(" ", withString: "_", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) 
      .stringByReplacingOccurrencesOfString("-", withString: "_", options: NSStringCompareOptions.CaseInsensitiveSearch, range: nil) 
     return cleanAppName 
    } 
} 

class Foo: NSObject { 
} 

此代码的输出将是:

The type of the array elements = Foo 
An instance of the array element = <EVReflection_iOS_Tests.Foo: 0x7fd6c20173d0> 
An instance of the array element = Foo 
+0

我注意到代码中有错误。我向awnser添加了新的代码。 –

+1

我试图解决完全相同的问题JSON序列化/反序列化(因为我对我看到的几个库不满意)。我发布了这个问题,并在一个小时内发现了你的库,并愉快地扔掉了我写的所有代码 –

0
class Foo { 
    var foo: Int = 1 
} 
struct Boo { 
    var boo: String = "alfa" 
} 

func f(array: Any) { 
    let mirror = Mirror(reflecting: array) 
    let arraytype = mirror.subjectType 
    switch arraytype { 
    case is Array<Foo>.Type: 
     let fooArray = array as! Array<Foo> 
     print(fooArray) 
    case is Array<Boo>.Type: 
     let booArray = array as! Array<Boo> 
     print(booArray) 
    default: 
     print("array is not Array<Foo> nor Array<Boo>") 
     break 
    } 
} 
var fooArray : Array<Foo> = [] 
fooArray.append(Foo()) 
var anyArray : Any = fooArray // cast as Any 
f(anyArray)      // [Foo] 
var booArray : Array<Boo> = [] 
booArray.append(Boo()) 
anyArray = booArray    // cast as Any 
f(anyArray)      // [Boo(boo: "alfa")] 
var intArray : Array<Int> = [] 
anyArray = intArray    // cast as Any 
f(anyArray)      // array is not Array<Foo> nor Array<Boo> 
+0

这将是一种工作。但是,每次需要支持新类型时,我都必须扩展开关盒。我正在寻找一些更通用的方法 –

+0

通用的方法?同比仍然需要知道如何使用不同类型的表演。 – user3441734

相关问题