0

Is there anyway to use conversion using a variable? I am using object stacking using type of "AnyObject" and I've been able to take the class type and populate a variable. Now I need to populate an array using conversion.

var myString = "Hello World"
var objectStack = [AnyObject]()

objectStack.append(myString)

let currentObject = String(describing: objectStack.last!)
var objectType = String()
let range: Range<String.Index> = currentObject.range(of: ":")!
objectType = currentObject.substring(to: range.lowerBound)
let range2: Range<String.Index> = objectType.range(of: ".")!
objectType = objectType.substring(from: range2.upperBound)

The code above will evaluate the class and set the value of "objectType" to "String". Now I'm trying to go the other way. Something like this:

for obj in objectStack{
    obj = newObject as! objectType //this doesn't work
}

Is something like this possible?

GED125
  • 476
  • 4
  • 18
  • Well no, because `objectType` is a `String` and not a metatype. But even if it was a metatype, it's value wouldn't be known until runtime, so what use would it be at compile time? To put it another way, what would you expect `obj` to be *statically* typed as? – Hamish Feb 12 '17 at 21:55
  • @Hamish, I could very well be going about this the wrong way. Perhaps I need to rethink it and go back to the drawing board. – GED125 Feb 12 '17 at 22:00
  • Quite probably – in general, you should avoid the use of `Any`/`AnyObject`, [there is nearly always a more descriptive type available to you](http://stackoverflow.com/q/37299843/2976878). What types of values are you planning on putting into `objectStack`? Are they related in some way? – Hamish Feb 12 '17 at 22:07

2 Answers2

0

There is a simpler, safer way to get the type:

let type = type(of: objectStack.last!)     // String.Type
let typeString = String(describing: type)  // "String"

The other way around is not possible because the type of the object is not known at compile time. Do you have a number of known types you want to try to cast to? In that case, use optional binding to check if the cast is successful:

let object = objectStack.last!
if let string = object as? String {
     // do String stuff
}
else if let i = object as? Int {
     // do Int stuff
}
// and so on

If you have a large number of possible types that share some common functionality: Use Protocols. See Swift Documentation for a nice introduction.

You define a protocol for some common functionality that different types can implement:

protocol Stackable {
    func doStuff()
    // (more methods or properties if necessary)
}

The protocol provides a contract that all types conforming to this protocol have to fulfill by providing implementations for all declared methods and properties. Let's create a struct that conforms to Stackable:

struct Foo: Stackable {
    func doStuff() {
        print("Foo is doing stuff.")
    }
}

You can also extend existing types to make them conform to a protocol. Let's make String Stackable:

extension String: Stackable {
    func doStuff() {
        print("'\(self)' is pretending to do stuff.")
    }
}

Let's try it out:

let stack: [Stackable] = [Foo(), "Cat"]

for item in stack {
    item.doStuff()
}

/*
prints the following:
    Foo is doing stuff.
    'Cat' is pretending to do stuff.
*/
nils
  • 1,786
  • 13
  • 18
  • This is what I'm doing currently, although I'm using a switch. The problem is that there are LOTS of possible object types in my application. I was hoping to avoid having to build a switch case for each, but it's starting to look like that is unavoidable? – GED125 Feb 12 '17 at 22:06
  • Do the object types have functionality in common? If yes: use protocols. https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Protocols.html – nils Feb 12 '17 at 22:09
  • thank you. I will start researching this. I think I need to call it a day, my head is starting to hurt from being such a newb. ;) – GED125 Feb 12 '17 at 22:11
  • Sure thing. I updated my answer with some hints to get you started with protocols. – nils Feb 12 '17 at 22:34
0

This worked for me:

var instance: AnyObject! = nil
let classInst = NSClassFromString(objectType) as! NSObject.Type
instance = classInst.init()
GED125
  • 476
  • 4
  • 18