Swift: Creating a factory function that takes a class type as a parameter, and outputs a constructor of that class

I’d like to create a factory function that takes in an class type and returns a constructor, so that I can use that constructor to create an instance of that class later.

Imagine I have two classes, Apple and Orange, which are both subclasses of Fruit. They need to be initialized with an unknownNumber which I will only know about later.

  • Nil is not compatible with expected argument type UIViewAnimationOptions
  • Get path to Swift script from within script
  • 'self' used before all stored properties are initialized
  • Swift file - how to disable all warnings?
  • How to use both google+ and facebook login in same appdelegate.swift
  • Firebase query sort order in swift?
  • class Apple: Fruit {
        init(unknownNumber: Int) {
            ...
        }
    }
    
    class Orange: Fruit {
        init(unknownNumber: Int) {
            ...
        }
    }
    

    I’d like to create a factory function that takes in a Class type, so that I can later call this function and initialize the specific subclass of Fruit, with the unknownNumber.

    //concept:
    func makeFruit(typeOfFruit) -> (Int) -> Fruit {
        return { (unknownNumber: Int) -> Fruit in
            return typeOfFruit(unknownNumber)
        }
    }
    

    To create an orangeFactory, then, I can do:

    let orangeFactory = makeFruit(Orange)    
    
    // then at a later time when I have the unknown number
    let orangeInstance = orangeFactory(unknownNumber)
    

    I am aware of the option of simply making the unknownNumber a lazy variable, but in my specific case the unknownNumber is not just a number and it involves other processes, so I’d like to only create the object when I have everything available, to keep the structure simple.

    Is something like this possible in Swift? I’ve been researching for a while online and couldn’t seem to find any direct answers. Any help would be greatly appreciated!

    3 Solutions Collect From Internet About “Swift: Creating a factory function that takes a class type as a parameter, and outputs a constructor of that class”

    Let’s work backwards. In your makeFruit function, you’ll need to declare the typeOfFruit parameter as a metatype of your Fruit superclass and explicitly reference the initializer:

    func makeFruit(typeOfFruit: Fruit.Type) -> (Int) -> Fruit {
        return { (unknownNumber: Int) -> Fruit in
            return typeOfFruit.init(unknownNumber: unknownNumber)
        }
    }
    

    You can only access required initializers on a metatype, so that init needs to be marked as such:

    class Fruit {
        required init(unknownNumber: Int) {
            // ...
        }
    }
    

    The rest should just work:

    let orangeMaker = makeFruit(Orange.self)
    let tenOranges = orangeMaker(10)
    

    If you are going to use the class itself as the identifier for a factory entry, you don’t actually need a factory. The factory pattern creates an indirection between an arbitrary identifier and a corresponding class of object.

    A simple way to do this in Swift is to use a dictionary:

    var fruitFactory:[String:Fruit.Type] = [:]
    
    fruitFactory["Apple"]   = Apple.self
    fruitFactory["Orange"]  = Orange.self
    fruitFactory["Banana"]  = Fruit.self
    fruitFactory["Grape"]   = Fruit.self
    
    let tenOranges = fruitFactory["Orange"]!.init(unknownNumber:10)
    

    note that your initializer in the Fruit class needs to be marked as required for this to work.

    You can declare Fruit as a protocol that exposes the required init method, and make use of the generics support in Switf:

    protocol Fruit {
        init(unknownNumber: Int)
    }
    
    class Apple: Fruit {
        required init(unknownNumber: Int) {
    
        }
    }
    
    class Orange: Fruit {
        required init(unknownNumber: Int) {
    
        }
    }
    
    func makeFruit<T: Fruit>(cls: T.Type) -> Int -> T {
        return { T(unknownNumber: $0) }
    }
    
    makeFruit(Apple.self)(10)  // returns an Apple
    makeFruit(Orange.self)(15) // returns an Orange
    

    This also gets you type safety as the result of the makeFruit function is the same as the type specified by the cls parameter.

    Note that this is not a factory function, but merely a forwarding one. But you can go even further and customize makeFruit for some of the fruits, and this is what is making it a factory function:

    class Apple: Fruit {
        required init(unknownNumber: Int) {
    
        }
    
        init(color: String, unknownNumber: Int) {
    
        }
    }
    
    func makeFruit<T: Fruit>(cls: T.Type) -> Int -> T {
        return { T(unknownNumber: $0) }
    }
    
    func makeFruit(cls: Apple.Type) -> Int -> Apple {
        return { Apple(color: "red", unknownNumber: $0) }
    }
    
    makeFruit(Orange.self)(15)  // an Orange
    makeFruit(Apple.self)(10)   // a red Apple
    

    Assuming that the Apple class has an initializer that accept a color, we can override makeFruit for this specific class and pass a default color (or maybe a computed one, depending of the factory specifications). This without losing the type safety that grows on you with Swift.