如何在Swift中types化一个子类UIViewController?

我试图用故事板快速testingUITableViewController的子类。 我能够得到一个对视图控制器的引用并logging下来,但我无法将它转换为我正在testing的类,所以我无法访问方法,属性等。

掌握我的课程实例的正确方法是什么?

testing场景:

 import XCTest import UIKit class GameListControllerTest: XCTestCase { var storyboard = UIStoryboard(name: "Main", bundle: nil) var _sut: AnyObject? var sut: AnyObject { if(_sut?) { return _sut! } _sut = storyboard.instantiateViewControllerWithIdentifier("GameListController") return _sut! } override func setUp() { super.setUp() println() println("=================================") println("sut \(sut)") println("view \(sut.view)") println("=================================") } func testInstance() { var vc1 = sut as UITableViewController var vc2 = sut as? GameListController println() println("=================================") println("VC1 \(vc1)") println("VC2 \(vc2)") println("=================================") } } 

输出:

 XCTestOutputBarrierTest Suite '_TtC15mytabletopTests22GameListControllerTest' started at 2014-06-16 06:13:30 +0000 XCTestOutputBarrierTest Case '-[_TtC15mytabletopTests22GameListControllerTest testInstance]' started. XCTestOutputBarrier ================================= sut <_TtC10mytabletop18GameListController: 0xb338d50> view <UITableView: 0xc033800; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0xb344960>; layer = <CALayer: 0xb33c7d0>; contentOffset: {0, 0}; contentSize: {480, 0}> ================================= ================================= VC1 <_TtC10mytabletop18GameListController: 0xb338d50> VC2 nil ================================= Test Case '-[_TtC15mytabletopTests22GameListControllerTest testInstance]' passed (0.007 seconds). XCTestOutputBarrierTest Suite '_TtC15mytabletopTests22GameListControllerTest' passed at 2014-06-16 06:13:30 +0000. Executed 1 test, with 0 failures (0 unexpected) in 0.007 (0.010) seconds 

如果我试图强制types转换( sut as GameListController ),我得到一个运行时exception。

这是发生了什么事。 我耗费了数天的时间,但是我的问题在于我的课程如何输出到目标:

文件检查器目标成员不正确与正确

这导致了我的课程的两个二进制副本,一个在应用程序目标和另一个在testing目标。 如果我们更加关注日志,我们可能会注意到:

 Test Case '-[_TtC15mytabletopTests22GameListControllerTest testInstance]' 

以上是testing方法testInstance ,它是mytabletopTests执行上下文的一部分。 现在让我们来看看从Storyboard中拉出的实例:

 sut <_TtC10mytabletop18GameListController: 0xb338d50> 

这反过来又在mytabletop上下文中运行。 这就解释了为什么testing不能绑定到GameListController 。 它知道的GameListController是在testing目标内编译的。

由于从testing目标中移除类使得该类对我的testing用例是未知的,现在我需要将我的app目标导入到testing用例中:

 import XCTest import UIKit import mytabletop // LINE ADDED class GameListControllerTest: XCTestCase { 

现在,testing可以访问的唯一的GameListController与故事板实例化的相同,我终于可以input它了。 这是新的testing用例:

 import XCTest import UIKit import mytabletop class GameListControllerTest: XCTestCase { let sut: GameListController = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("GameListController") as GameListController override func setUp() { super.setUp() UIApplication.sharedApplication().keyWindow.rootViewController = sut XCTAssertNotNil(sut.view) } func testInstance() { XCTAssertNotNil(sut) XCTAssertNotNil(sut.tableView) // UITableViewController property XCTAssertNotNil(sut.store) // instance property XCTAssertNotNil(sut.someButton) // outlet } } 

现在,我可以在实例初始化期间正确地进行types转换(滚动查看as GameListController )。 为了强制所有的插口被正确的绑定和子视图相应的渲染设备,testing正在运行,我们可以使视图控制器成为应用程序的rootViewController ,并从中拉取视图,如上面的setUp函数所示。 即使myCustomOutlet现在正常工作。