替代Swift中的load方法

时间:2015-04-18 16:16:55

标签: objective-c swift

我正在开发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类方法。没有这个,我不知道允许类自动向工厂注册的机制。

我想知道是否还有其他办法让注册工作。

哪些替代品可以允许课程在工厂注册,或者可以使用哪些其他技术来完成工厂提供的相同类型的松耦合?

2 个答案:

答案 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)
    }
}