Alternative boot method in Swift

I am working on developing an application in Swift. I wanted to create a system for an application that would allow you to freely communicate between objects, and one strategy (which I have successfully used in other languages) was to create what I call the factory instance. This is pretty simple, and here is the main implementation I came across in Swift:

import Foundation private var typeGenerators = Dictionary<String, InstanceFactory.GeneratorCallback>() public class InstanceFactory: NSObject { public typealias GeneratorCallback = () -> AnyObject! public class func registerGeneratorFor(typeName: String, callback: GeneratorCallback) { typeGenerators[typeName] = callback } public class func instanceOf(typeName: String) -> AnyObject! { return typeGenerators[typeName]?() } } 

The idea is that when an instance of an object needs access to another instance of the object, and not to create that instance, which would connect the two objects more tightly, the first object would be postponed to factory to provide the necessary instance by calling the instanceOf method. The factory will know how to provide different types of instances, because these types will be registered with the factory and provide a closure that the instance could generate.

The trick is how to get classes to register with factory. I had previously done a similar factory in Objective-C, and the way I got the registration to work was to override the + load method for each class that needs to be registered with factory. This worked fine for Objective-C, and I figured it could work for Swift, as I would limit the factory to only providing objects derived from NSObject. It turned out that I got this to work, and I spent a lot of effort developing classes to use the factory.

However, after upgrading to Xcode 6.3, I found that Apple had banned the use of the load class method in Swift. Without this, I don’t know about the mechanism that allows classes to automatically register with the factory.

I am wondering if there is another way to make registration work.

What alternatives exist that could allow classes to register with the factory, or what other methods could they use to perform the same loose coupling as factory?

+6
source share
2 answers

I found a possible solution to your problem after I wanted to register all ViewControllers that will use a specific protocol in my application, and I came across this question and a possible answer.

The original was posted here: How to list all classes that comply with the protocol in Swift?

I adapted it to Swift 3 and made it a little faster and more versatile:

 import UIKit class ContextRoute: NSObject { } @objc protocol ContextRoutable { static var route: ContextRoute { get } } class ContextRouter: NSObject { private static var storedRoutes: [ContextRoute]? static var routes: [ContextRoute] { get { if let storedRoutes = storedRoutes { return storedRoutes } let routables: [ContextRoutable.Type] = classes(implementing: ContextRoutable.self) let newRoutes = routables.map { routable in routable.route } storedRoutes = newRoutes return newRoutes } } private class func classes<T>(implementing objcProtocol: Protocol) -> [T] { let classes = classList().flatMap { objcClass in objcClass as? T } return classes } private class func classList() -> [AnyObject] { let expectedClassCount = objc_getClassList(nil, 0) let allClasses = UnsafeMutablePointer<AnyClass?>.allocate(capacity: Int(expectedClassCount)) let autoreleasingAllClasses = AutoreleasingUnsafeMutablePointer<AnyClass?>(allClasses) let actualClassCount:Int32 = objc_getClassList(autoreleasingAllClasses, expectedClassCount) var classes = [AnyObject]() for i in 0 ..< actualClassCount { if let currentClass: AnyClass = allClasses[Int(i)], class_conformsToProtocol(currentClass, ContextRoutable.self) { classes.append(currentClass) } } allClasses.deallocate(capacity: Int(expectedClassCount)) return classes } } 

I tried this in my application and it works. I synchronized it in the simulator and it takes 0.05 s for an application that has about 12,000 classes.

+2
source

Instead, consider the Swift approach using the protocol. I think the solution is actually simpler than the Objective-C approach. There are variations of this with Self restrictions, which are even better if you have more control over classes.

 // define a protocol to create an instance of a class protocol FactoryInstantiable { static func makeFactoryInstance() -> AnyObject } // Factory for generating new instances public class InstanceFactory: NSObject { public class func instanceOf(typeName: String) -> AnyObject! { if let ProductType = NSClassFromString(typeName) as? FactoryInstantiable.Type { return ProductType.makeFactoryInstance() } else { return nil } } } // your class which generally could be defined somewhere else class MyClass { var counter : Int init(counter: Int) { self.counter = 0 } } // extension of your class to conform to the FactoryInstantiable protocol extension MyClass : FactoryInstantiable { static func makeFactoryInstance() -> AnyObject { return MyClass(counter: 0) } } 
0
source

Source: https://habr.com/ru/post/985429/


All Articles