私はView Controllerに対して単体テストを実行しています。このスイートには2つのビューコントローラがあり、そのうちの1つはストーリーボードファイル内の別のビューコントローラにつながります。UIStoryboardSceneは保持カウントを変更せずにコントローラを予期せずに割り当て解除します
両方のコントローラのテストでは、私は同じ方法でテスト対象を作成します。にstoryboardWithName:factory:bundle:
(依存性注入のための台風は工場出荷時のものを使用します)を取得します。次に、storyboard.instantiateViewControllerWithIdentifier:
を使用してVCを取得します。
私の最初のView Controllerのテストでは、すべてのテストに合格します。重要なのは、ビュー・コントローラのdeinit
メソッドは、vc自体がテスト・ケース内のスコープから外れるか、または新しいインスタンスがサブジェクトになり、古いインスタンスの保持カウントが0に減少した場合にのみ呼び出されることです。
ただし、 2番目のVCでは、何らかの理由で[UIStoryboardScene dealloc]
にコールが発信され、コントローラのdeinit
がコールされるため、これらのいずれの場合もテストは失敗します(VCが範囲外になるか、新しいVCが対象外になる)その保持カウントは依然として1でなければならない(テストケースによって保持される)。 ARCは、新しいインスタンスをサブジェクトとして設定すると、VCに別のリリースメッセージを送信し、EXC_BAD_ACCESS (CODE=i386, GPFLT)
を取得します。
[UIStoryboardScene dealloc]
は、XCTestフレームワーク(ここではコピーされています)でコンパイルされたコードの集まりで発生しますが、テストケースが終了しているために起こっていると思います。
* thread #1: tid = 0x57cf91, 0x00000001089953a3 sbprod`Mode2ViewController.__deallocating_deinit(self=0x00007fd2bbdde5d0) + 19 at Mode2ViewController.swift:68, queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
* frame #0: 0x00000001089953a3 sbprod`Mode2ViewController.__deallocating_deinit(self=0x00007fd2bbdde5d0) + 19 at Mode2ViewController.swift:68
frame #1: 0x0000000108995492 sbprod`@objc Mode2ViewController.__deallocating_deinit + 34 at Mode2ViewController.swift:0
frame #2: 0x000000010a1ff702 UIKit`-[UIStoryboardScene dealloc] + 36
frame #3: 0x000000010b04dafe libobjc.A.dylib`objc_object::sidetable_release(bool) + 232
frame #4: 0x000000010b04e0b8 libobjc.A.dylib`(anonymous namespace)::AutoreleasePoolPage::pop(void*) + 488
frame #5: 0x0000000115841f37 XCTest`__24-[XCTestCase invokeTest]_block_invoke_2 + 430
frame #6: 0x0000000115876613 XCTest`-[XCTestContext performInScope:] + 190
frame #7: 0x0000000115841d78 XCTest`-[XCTestCase invokeTest] + 169
frame #8: 0x00000001158423a2 XCTest`-[XCTestCase performTest:] + 459
frame #9: 0x000000011583fcf7 XCTest`-[XCTestSuite performTest:] + 396
frame #10: 0x000000011583fcf7 XCTest`-[XCTestSuite performTest:] + 396
frame #11: 0x000000011583fcf7 XCTest`-[XCTestSuite performTest:] + 396
frame #12: 0x000000011582cb10 XCTest`__25-[XCTestDriver _runSuite]_block_invoke + 51
frame #13: 0x000000011584db4c XCTest`-[XCTestObservationCenter _observeTestExecutionForBlock:] + 640
frame #14: 0x000000011582ca55 XCTest`-[XCTestDriver _runSuite] + 453
frame #15: 0x000000011582d7d1 XCTest`-[XCTestDriver _checkForTestManager] + 259
frame #16: 0x0000000115877a9a XCTest`_XCTestMain + 628
:
UIStoryboardSceneが全く作成されているのはなぜ?私は、私のテストのためにシーン、VCだけを望んでいません。以前のテストケースでは発生していないようです。ストーリーボードが2つのVCの間で気にする限り、唯一の違いは、そのうちの1つがその中に入り組んでいることと、もう1つがそれから出ていることです。 UIStoryboardSceneは両方のケースでは、既存の事実であるならば、なぜそれが
deinit
は、それがするべき前に私のVCをINGののですか?
私のテストケースにも適用範囲内で互いに非常に異なっていない、しかし、このテストケースは場所にいくつかのクロージャを渡し、私は、クロージャがARCにどのような影響を与えるかについては100%ではないです。
EDIT:ここに示す関連するコード。
override func spec() {
var subject: Mode2ViewController!
let presentDisplayString = "DesiredString"
describe("Mode2ViewController") {
describe("loading") {
describe("date and location") {
context("when location is available") {
beforeEach {
let system = MockSystemComponents.CreateWith(location: true, groups: nil)
let assembly = ApplicationAssembly().activateWithCollaboratingAssemblies([
system
])
//crash occurs on next line, before the 2nd test case, because the
//old subject has already been deallocated (by UIStoryboardScene)
//but reassigning this var, which had retains it, triggers a release
subject = assembly.mode2ViewController() as! Mode2ViewController
let _ = subject.view
}
it("records the location") {
expect(subject).notTo(beNil())
}
it("displays the location as a meaningful string") {
expect(subject.locationLabel.text).to(equal(presentDisplayString))
}
}
}
}
}
}
注:クイック用いて行われる私のテストケースにおいて
(最初の編集)上記で与えられたスタックトレースは、私はMode2ViewController.deinit()
に挿入されたブレークポイントです。
コードを表示する必要があります。 – jtbandes
@jtbandes第2(クラッシュ)リリースを呼び出すコードを追加しました。他のコードが必要な場合はお知らせください。 – Quintana