swiftfluentmethod-chainingmethodology

Swift method chaining, how to reuse classes and methods?


Consider the following example

class ClassA {
    
    func createAnInstanceOfAnotherClass() -> AnotherClass {

        return AnotherClass()
    }
    
    func callMeA() {
        
    }
}

class ClassB {
    func createAnInstanceOfAnotherClass() -> AnotherClass {

        return AnotherClass()
    }
    
    func callMeB() {
        
    }
}

class AnotherClass {
    func doSomethingAndReturn() {
        return
    }
}

class MethodChain {
    func methodChainTest() {
        ClassA()
            .createAnInstanceOfAnotherClass()
            .doSomethingAndReturn() //return to ClassA
            .callMeA() // call classA callMe
        
        ClassB()
            .createAnInstanceOfAnotherClass()
            .doSomethingAndReturn() // return to ClassB
            .callMeB() // call ClassB callMe
    }
}

Is it possible for the class AnotherClass to return the instance of the class that created it? In this example I want to use the class method doSomethingAndReturn when method chaining with both ClassA and ClassB and then contione the method chain with methods from either ClassA or ClassB


Solution

  • You could make AnotherClass generic with a type parameter Creator, which stores the type of its creator.

    class ClassA {
        
        func createAnInstanceOfAnotherClass() -> AnotherClass<ClassA> {
    
            return AnotherClass(creator: self)
        }
        
        func callMeA() {
            
        }
    }
    
    class ClassB {
        func createAnInstanceOfAnotherClass() -> AnotherClass<ClassB> {
    
            return AnotherClass(creator: self)
        }
        
        func callMeB() {
            
        }
    }
    
    class AnotherClass<Creator: AnyObject> {
        // weak to avoid retain cycles!
        private weak var creator: Creator?
        
        init(creator: Creator) {
            self.creator = creator
        }
        
        func doSomethingAndReturn() -> Creator {
            // assuming you always do method chaining, 
            // and not do something weird with the intermediate results,
            // this should be safe to unwrap forcefully
            creator!
        }
    }