2015-04-18 3 views
6

Я работаю над разработкой приложения в 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. Без этого я не знаю о механизме, позволяющем классам автоматически регистрироваться на заводе.

Мне интересно, есть ли другой способ заставить регистрацию работать.

Какие существуют альтернативы, которые могут позволить занятиям на заводе-изготовителе или какие другие методы могут быть использованы для выполнения той же самой свободной связи, которую завод предоставляет?

+0

Вы можете продолжить использовать Objective-C для этой части ...? – matt

+0

Да, я мог бы использовать Objective-C для этого. Из того, что я вижу, недостатком этого является введение дополнительных модулей для каждого класса, который должен регистрироваться на заводе, что может и не быть проблемой. Разумеется, я мог бы просто разбить всю регистрацию на один + метод загрузки для одного класса. Однако, если бы я сделал это, я мог бы так же легко сделать регистрацию в модуле Swift, как и делегирование приложения. –

+0

Если бы мне пришлось использовать модули mulitple, возможно, я даже мог бы зарегистрироваться в Objective-C++.Я подозреваю, что все модули регистрации будут делать почти то же самое, поэтому было бы неплохо объединить эту функциональность. Я не думал об этом полностью, но похоже, что кто-то может создать шаблон C++ в Objective-C++, который может содержать плиту котла для регистрации. Опять же, вероятно, не слишком много задействованного кода, так что, возможно, это не стоит усилий. –

ответ

0

Рассмотрите возможность использования Swift с использованием протокола. Я думаю, что решение на самом деле проще, чем подход Objective-C. Существуют вариации этого с ограничениями Self, которые даже лучше, если у вас есть больший контроль над классами.

// 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) 
    } 
} 
+1

Возможно, мне что-то не хватает, однако, глядя на предлагаемую реализацию, он, кажется, побеждает весь объект InstanceFactory. Приложение InstanceFactory предназначено для обеспечения свободной связи между экземпляром класса и пользователем этого экземпляра. С первоначальной реализацией, учитывая какой-то идентификатор, завод может производить произвольный экземпляр. Использование NSClassFromString, как представляется, позволяет повторно установить тугое соединение, которое фабрика пыталась избежать, поскольку NSClassFromString предоставит один и только один класс, который соответствует строковому идентификатору. –

+0

Мне трудно понять, как кто-то может настроить фабрику для предоставления производного экземпляра вместо этого или предоставить фабрике возможность предоставить экземпляр для указанного протокола. Мне интересно, есть ли альтернатива NSClassFromString, которая может быть использована вместо этого. –

+0

О, я вижу. Вы хотите иметь собственный идентификатор имени типа. В этом случае, я думаю, ваш единственный вариант - назначить идентификаторы классам извне (например, на вашем фабричном или вспомогательном классе), а не изнутри ваших классов, как вы упомянули в одном из ваших предыдущих комментариев. Каждый раз, когда вы добавляете новый класс, вам нужно будет изменить вспомогательный класс для его регистрации. Разве это не лучше, чем исходный подход Objective-C? Он перемещает регистрацию в одно место и позволяет настраивать, какие классы зарегистрированы, на какие идентификаторы для разных вариантов использования. –

2

Я нашел возможное решение проблемы после того, как я хотел, чтобы зарегистрировать все ViewControllers, которые будут реализующие определенный протокол в моем приложении, и я столкнулся как этот вопрос и возможный ответ.

Оригинал был размещен здесь: How to list all classes conforming to protocol in Swift?

Я приспособил его Swift 3 и сделал это немного более Swift-й и общий:

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 с.

Смежные вопросы