-1

I am trying to analyze type information in Swift 2.0 - and store it in a static structure - but am stuck. The most promising approach is to create a mirror for an instance - which would be done once on demand, assuming a default init - and to look at the subjectType of the mirror elements.

My questions are:

  • How to unwrap optional types ( e.g. Optional<String> ). I would like to have the String part as a type.
  • How to determine generic array types, e.g. Array<Foo>.

Parsing the string is silly and it's probably not possible..

Other questions related to arrays: If a have the element type, how do i create a new instance?

To make it clearer. I need the type information for higher level algorithms such as mappers - object mappers, json mappers, widget mappers, etc. - that require information on the type of involved objects trying to be type safe or by inserting appropriate conversions, if needed.

Think of a property Int that needs to be mapped to a Int? property which should not raise an exception.

The code so far fills a BeanDescriptor class that contains an array of PropertyDescriptor's that should store all required information

Something like:

class PropertyDescriptor {
   // instance data

   var bean: BeanDescriptor;
   var name: String;
   var type: Any.Type;
   var optional = false
   // more data for arrays, e.g. elementType...
   ...
}

Code so far to analyze a class is:

// create a default instance
let instance  = create(); // we need a NSObject though! darn...
let mirror = Mirror(reflecting: instance)
if let displayStyle = mirror.displayStyle {
  if displayStyle == .Class {
     for case let (label?, value) in mirror.children {
        let property = analyzeProperty(label, value: value)

        properties[property.name] = property;
      } // for
   }
}

and the called function

func analyzeProperty(name : String, value: Any) -> PropertyDescriptor {
    let mirror : Mirror  = Mirror(reflecting: value)
    var type = mirror.subjectType
    var optional = false

    // no way..this sucks!

    if (type == String?.self) {
        type = String.self // uhhhh
        optional = true
    }
    else if ... // lots other literal types, ...

    return PropertyDescriptor(bean: self, name: name, type: type, optional: optional)
}

But this will not cover other optional classes Money? as well as other information with respect to arrays, e.g. Array<Money>, or Array<Money?> where i would detect an array type and would have to determine the element type

  • 1
    I'm having a hard time understanding what you want. Do you think you could post some code? Something showing what you have, what you desire, and possibly pseudo code that shows what you're thinking? – solidcell Jul 06 '16 at 11:39
  • edited the question :-) – Andreas Ernst Jul 07 '16 at 12:45

2 Answers2

0

If I understand your question correctly you want to analyse a class and find the type of each property? I had the same need and I finally got it working.

I have a solution that finds the name and type of a property given any class that inherits from NSObject.

I wrote a lengthy explanation on StackOverflow here, and my project is available here on Github,

In short you can do something like this (but really check out the code Github):

public class func getTypesOfProperties(inClass clazz: NSObject.Type) -> Dictionary<String, Any>? {
    var count = UInt32()
    guard let properties = class_copyPropertyList(clazz, &count) else { return nil }
    var types: Dictionary<String, Any> = [:]
    for i in 0..<Int(count) {
        guard let property: objc_property_t = properties[i], let name = getNameOf(property: property) else { continue }
        let type = getTypeOf(property: property)
        types[name] = type
    }
    free(properties)
    return types
}
Community
  • 1
  • 1
Sajjon
  • 8,938
  • 5
  • 60
  • 94
  • thanks for the reply. I tried that in the beginning, but it didn't work because it didn't help me with optionals and also showed some strange results with different data types ( numeric stuff ). In the end i stayed with the solution to create a prototype object and use a mirror. Together with extensions to array and optional i am able to determine most of the interesting stuff ( except implemented protocols ). You can see the results here: https://github.com/coolsamson7/inject/blob/master/Inject/beans/BeanDescriptor.swift – Andreas Ernst Sep 05 '16 at 08:42
  • question answered? :-) – Andreas Ernst Sep 05 '16 at 08:51
  • Yes it is a limitation within class_copyPropertyList, it can't find optional value types... – Sajjon Sep 05 '16 at 08:53
-1

how to determine generic array types, e.g. "Array< Foo >"

Please take a look at this SO question. You will find out, that it is currently only possible for non-empty arrays, as empty arrays are found as Array<AnyObject>.

If a have the element type, how do i create a new instance?

The following example show how to init an object by its type. This can be done for all types, as long as the have an (empty) init() constructor.

let myType = ...//your code for getting the type
let object: MyObject = myType.init()
Community
  • 1
  • 1
mad_manny
  • 1,081
  • 16
  • 28