Well, that's not really any different than a switch statement, in that it has 
to be maintained.

> On Nov 15, 2016, at 01:50 , Jeremy Pereira <jeremy.j.pere...@googlemail.com> 
> wrote:
> 
> Perhaps I’m missing something here, but why not use a map?
> 
>    let factoryMap = [ String : () -> SuperClassOrCommonProtocol ] = [ 
> “MySubClass" : { return MySubClass() }, … ]
> 
>    …
> 
>    guard let factoryMethod = factoryMap[theClassName] else { /* error */ }
>    return factoryMethod()
> 
> This is an approach I always ended up taking in Objective-C anyway, because, 
> if you don’t know what’s in the string, you need to validate it (imagine if 
> the user of your app finds out that they can cause you to instantiate any 
> arbitrary class) and if you do know what’s in the string, why are you not 
> creating the instance directly?
> 
> 
>> On 14 Nov 2016, at 23:48, Rick Mann via swift-users <swift-users@swift.org> 
>> wrote:
>> 
>> Thanks, David. That's interesting as a thought exercise, but doesn't really 
>> get me away from having switch statements. I'll probably end up just 
>> "slightly polluting" my classes by adding extension methods to create the 
>> appropriate auxiliary classes. Sure wish Swift supported optional methods 
>> without @objc (I guess it's not that big a deal to use @objc).
>> 
>>> On Nov 13, 2016, at 11:19 , David Sweeris <daveswee...@mac.com> wrote:
>>> 
>>> 
>>>> On Nov 13, 2016, at 1:55 AM, Rick Mann <rm...@latencyzero.com> wrote:
>>>> 
>>>> 
>>>>> On Nov 12, 2016, at 22:47 , David Sweeris <daveswee...@mac.com> wrote:
>>>>> 
>>>>> 
>>>>>> On Nov 13, 2016, at 00:38, Rick Mann via swift-users 
>>>>>> <swift-users@swift.org> wrote:
>>>>>> 
>>>>>> So, it seems there's still no way to do something like instantiate a 
>>>>>> class given only its name (as a String)?
>>>>>> 
>>>>>> In my situation, I have a number of subclasses (or protocol 
>>>>>> implementations), which parallel some other class hierarchy. I need to 
>>>>>> dynamically create one based on the name of another. I don't want the 
>>>>>> latter classes to "know" anything about the former.
>>>>> 
>>>>> Not that I know of... If this is all your code, can you fake it by 
>>>>> switching over the type's name?
>>>> 
>>>> Yeah, it just happens in a few places, would be nice to write the code 
>>>> once and then just ensure classes exist. I know I could do it subclassing 
>>>> NSObject, but Swift really ought to have proper reflection.
>>> 
>>> Reflection is on the todo list (although I can’t recall if it’s in-scope 
>>> for Swift 4).
>>> 
>>> There’s also the possibility of putting the names of the classes you want 
>>> to instantiate into an enum. In fact, if all the classes in question have a 
>>> common superclass, you could this:
>>> class MyAwesomeSuperClass { required init() {} }
>>> class MyAwesomeSubClass : MyAwesomeSuperClass {}
>>> class Whatever : MyAwesomeSuperClass {}
>>> class Etc : Whatever {}
>>> enum ClassNames : String {
>>>   //Unfortunately the value of each case has to be a literal, so
>>>   //you can’t just say `case etc = "\(Etc.self)"`
>>>   case myAwesomeSuperClass = "MyAwesomeSuperClass"
>>>   case myAwesomeSubClass = "MyAwesomeSubClass"
>>>   case whatever = "Whatever"
>>>   case etc = "Etc"
>>>   init(_ instance: MyAwesomeSuperClass) { self = ClassNames.init(rawValue: 
>>> "\(type(of: instance))")! }
>>>   init(_ type: MyAwesomeSuperClass.Type) { self = ClassNames.init(rawValue: 
>>> "\(type)")! }
>>>   var type: MyAwesomeSuperClass.Type {
>>>       switch self {
>>>       case .myAwesomeSuperClass:  return MyAwesomeSuperClass.self
>>>       case .myAwesomeSubClass:    return MyAwesomeSubClass.self
>>>       case .whatever:             return Whatever.self
>>>       case .etc:                  return Etc.self
>>>       }
>>>  }
>>> }
>>> var etc = Etc()
>>> var className = ClassNames(etc)
>>> var newEtc = className.type.init()
>>> 
>>> The same trick works if all the types in question conform to the same 
>>> protocol, too:
>>> protocol MyAwesomeProtocol {
>>>   init()
>>>   func toIntMax() -> IntMax
>>> }
>>> extension Int : MyAwesomeProtocol {}
>>> struct Five : MyAwesomeProtocol { func toIntMax() -> IntMax { return 5 } }
>>> enum ProtocolNames : String {
>>>   case five = "Five"
>>>   case int = "Int"
>>>   init(_ instance: MyAwesomeProtocol) { self = ProtocolNames.init(rawValue: 
>>> "\(type(of: instance))”)! }
>>>   init(_ type: MyAwesomeProtocol.Type) { self = 
>>> ProtocolNames.init(rawValue: "\(type)")! }
>>>   var type: MyAwesomeProtocol.Type {
>>>       switch self {
>>>       case .five: return Five.self
>>>       case .int:  return Int.self
>>>       }
>>>   }
>>> }
>>> var five = Five()
>>> var fiveName = ProtocolNames(five)
>>> var newFive = fiveName.type.init()
>>> 
>>> Either way, though, you’ll have to do something like if let nf = newFive 
>>> as? Int {…} if you want to use any functionality that isn’t explicitly in 
>>> the superclass or protocol.
>>> 
>>> It certainly involves some boilerplate code, but it also has the advantages 
>>> of validating the name before you try to use it and ensuring that any 
>>> switch statements can actually handle all the classes. 
>>> 
>>> - Dave Sweeris
>> 
>> 
>> -- 
>> Rick Mann
>> rm...@latencyzero.com
>> 
>> 
>> _______________________________________________
>> swift-users mailing list
>> swift-users@swift.org
>> https://lists.swift.org/mailman/listinfo/swift-users
> 


-- 
Rick Mann
rm...@latencyzero.com


_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users

Reply via email to