> On Nov 15, 2016, at 05:24 , Jeremy Pereira <[email protected]>
> wrote:
>
>
>> On 15 Nov 2016, at 10:33, Rick Mann <[email protected]> wrote:
>>
>> Well, that's not really any different than a switch statement, in that it
>> has to be maintained.
>
> Yes, but I would argue that it is a good thing because you need to do some
> validation before you instantiate the class anyway.
>
> Furthermore, it gives you more flexibility in terms of initialisation because
> the closure can invoke any initialiser regardless of parameters and can do
> other processing as well.
Yeah, but that's not the flexibility I need. And with good
reflection/introspection, I can do all the validation I need dynamically. In an
ideal world, I could do something like this:
let pathRenderers = classesThatImplement(protocol: Renderer)
for pr in pathRenderers {
for ini in pr.initializers {
if ini.has(signature: (Path))
{
let renderer = pr.instantiate(aPath)
return
}
}
}
Obviously more complicated than this, but you get the idea.
>
>>
>>> On Nov 15, 2016, at 01:50 , Jeremy Pereira
>>> <[email protected]> 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
>>>> <[email protected]> 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 <[email protected]> wrote:
>>>>>
>>>>>
>>>>>> On Nov 13, 2016, at 1:55 AM, Rick Mann <[email protected]> wrote:
>>>>>>
>>>>>>
>>>>>>> On Nov 12, 2016, at 22:47 , David Sweeris <[email protected]> wrote:
>>>>>>>
>>>>>>>
>>>>>>>> On Nov 13, 2016, at 00:38, Rick Mann via swift-users
>>>>>>>> <[email protected]> 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
>>>> [email protected]
>>>>
>>>>
>>>> _______________________________________________
>>>> swift-users mailing list
>>>> [email protected]
>>>> https://lists.swift.org/mailman/listinfo/swift-users
>>>
>>
>>
>> --
>> Rick Mann
>> [email protected]
>>
>>
>
--
Rick Mann
[email protected]
_______________________________________________
swift-users mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-users