我正在开发Swift中的应用程序。我想为应用程序设计一个允许对象之间松散耦合的系统,而一个策略(我已经在其他语言中成功使用)就是创建一个我称之为实例工厂的东西。这很简单,这是我在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]?()
}
}
这个想法是当一个对象实例需要访问另一个对象实例时,而不是直接创建那个将两个对象紧密耦合的实例,第一个对象会通过调用instanceOf来推迟工厂提供所需的实例方法。工厂将知道如何提供各种实例类型,因为这些类型将向工厂注册并提供可生成实例的闭包。
诀窍是如何让类在工厂注册。我之前在Objective-C中创建了一个类似的工厂,我注册工作的方式是覆盖需要向工厂注册的每个类的+ load方法。这对Objective-C非常有用,我认为它也适用于Swift,因为我会限制工厂只提供从NSObject派生的对象。看来我已经开始工作了,我花了大量精力设计课程以利用工厂。
但是,在升级到Xcode 6.3后,我发现Apple不允许在Swift中使用load类方法。没有这个,我不知道允许类自动向工厂注册的机制。
我想知道是否还有其他办法让注册工作。
哪些替代品可以允许课程在工厂注册,或者可以使用哪些其他技术来完成工厂提供的相同类型的松耦合?
答案 0 :(得分:2)
在我想要注册所有将在我的应用程序中实现某个协议的ViewControllers之后,我找到了一个可能的问题解决方案,我遇到了这个问题和可能的答案。
原文发布在此处:How to list all classes conforming to protocol in Swift?
我将它改编为Swift 3并使其更加快速和通用:
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
}
}
我在我的应用程序中尝试了它并且它有效。我在模拟器中计时它,对于一个有大约12000个类的应用程序需要0.05秒。
答案 1 :(得分:0)
考虑使用协议代替Swift方法。我认为解决方案实际上比Objective-C方法更简单。如果您对类有更多控制权,那么自我约束就会有这种变化。
// 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)
}
}