我正在使用 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类方法。如果没有这个,我不知道有一种机制可以让类自动向工厂注册。
我想知道是否有其他方法可以使注册生效。
有哪些可用的替代方法可以允许类向工厂注册,或者可以使用哪些其他技术来实现工厂提供的相同类型的松散耦合?
最佳答案
在我想注册所有将在我的应用程序中实现某个协议(protocol)的 ViewController 之后,我找到了一个可能的解决方案,我遇到了这个问题和一个可能的答案。
原文发布于此:How to list all classes conforming to protocol in Swift?
我将其改编为 Swift 3 并使其更加 Swift-y 和通用:
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 秒。
关于objective-c - Swift 中 load 方法的替代方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29719773/
我正在学习如何使用Nokogiri,根据这段代码我遇到了一些问题:require'rubygems'require'mechanize'post_agent=WWW::Mechanize.newpost_page=post_agent.get('http://www.vbulletin.org/forum/showthread.php?t=230708')puts"\nabsolutepathwithtbodygivesnil"putspost_page.parser.xpath('/html/body/div/div/div/div/div/table/tbody/tr/td/div
总的来说,我对ruby还比较陌生,我正在为我正在创建的对象编写一些rspec测试用例。许多测试用例都非常基础,我只是想确保正确填充和返回值。我想知道是否有办法使用循环结构来执行此操作。不必为我要测试的每个方法都设置一个assertEquals。例如:describeitem,"TestingtheItem"doit"willhaveanullvaluetostart"doitem=Item.new#HereIcoulddotheitem.name.shouldbe_nil#thenIcoulddoitem.category.shouldbe_nilendend但我想要一些方法来使用
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
我正在尝试设置一个puppet节点,但rubygems似乎不正常。如果我通过它自己的二进制文件(/usr/lib/ruby/gems/1.8/gems/facter-1.5.8/bin/facter)在cli上运行facter,它工作正常,但如果我通过由rubygems(/usr/bin/facter)安装的二进制文件,它抛出:/usr/lib/ruby/1.8/facter/uptime.rb:11:undefinedmethod`get_uptime'forFacter::Util::Uptime:Module(NoMethodError)from/usr/lib/ruby
我想了解Ruby方法methods()是如何工作的。我尝试使用“ruby方法”在Google上搜索,但这不是我需要的。我也看过ruby-doc.org,但我没有找到这种方法。你能详细解释一下它是如何工作的或者给我一个链接吗?更新我用methods()方法做了实验,得到了这样的结果:'labrat'代码classFirstdeffirst_instance_mymethodenddefself.first_class_mymethodendendclassSecond使用类#returnsavailablemethodslistforclassandancestorsputsSeco
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
设置:狂欢ruby1.9.2高线(1.6.13)描述:我已经相当习惯在其他一些项目中使用highline,但已经有几个月没有使用它了。现在,在Ruby1.9.2上全新安装时,它似乎不允许在同一行回答提示。所以以前我会看到类似的东西:require"highline/import"ask"Whatisyourfavoritecolor?"并得到:Whatisyourfavoritecolor?|现在我看到类似的东西:Whatisyourfavoritecolor?|竖线(|)符号是我的终端光标。知道为什么会发生这种变化吗? 最佳答案
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳