2017-08-25 15 views
1

保持サイクルをチェックするテストを作成しようとしていますが、この奇妙な動作に遭遇しました。ビューコントローラをnilに設定すると、UIViewControllerのプロパティは割り当て解除されません。このモックオブジェクトを例に取ってみましょう:割り当て解除後にUIViewController変数が残る

class BasicViewController: UIViewController { 
    var someObject = NSObject() 
    ..... 
} 

これはすべて変数です。 basicViewController = nilを呼び出すと、someObjectがnilになることが想定されますが、そうでないと仮定します。 viewDidLoadviewDidAppearviewWillAppear -

it("releases someObject") { 
    var controller: MockController? = MockController() 
    weak var something = controller?.something 
    expect(controller).toNot(beNil()) 
    controller = nil 
    expect(controller).to(beNil()) 
    expect(something).to(beNil()) 
} 

it("doesn't release someObject") { 
    var controller: MockController? = MockController() 
    weak var something = controller?.something 
    expect(controller).toNot(beNil()) 
    _ = controller?.view 
    controller = nil 
    expect(controller).to(beNil()) 
    expect(something).toNot(beNil()) 
} 

vc.viewを呼び出すとき、これはloadViewなどUIViewControllerのライフサイクル関数を呼び出します。私の質問はなぜですか?なぜUIViewControllerviewプロパティを参照すると、UIViewControllernilに設定した後でも、UIViewControllerが所有するすべてのオブジェクトが保持されるのはなぜですか。オブジェクトは、プールから排出されたときに正確に決まりますautoreleasepoolを、追加

、そしてそれは同様に動作します:

FWIW、私はQuickとテストのためNimbleだけでなく、Swift 3.1

+0

しかし、2つのテストを見ると、2つのテストの唯一の違いは、私が_ = vc.viewを呼び出すことです。テストをパスするためにtoNot()を使用する必要があります。それは望ましくない。私はこの例を作成して、最も単純なオブジェクトでさえ、この永続性がどのように発生するかを示しました。何か強いリファレンスサイクルは起こっていません。何かは単なるNSObjectです。ビューとやりとりするとき、コントローラのプロパティは持続しますが、しばらくすると割り当てが解除されると私は信じています。 – jsetting32

答えて

1

短い答えを使用していますあなたは期待していたでしょう。


長い答え:

私はあなたが記述と同じ行動を経験しています。しかし、問題はView Controllerのプロパティではありません。これはビューコントローラ自体です。あなたの例では

、あなたはnilからcontrollerを設定し、それはコントローラの割り当てが解除されているか否かを推測することになりましnilであるという事実を使用して表示されています。しかし、これは、ビューコントローラへの特定の参照がnilであるかどうかをテストするだけですが、ビューコントローラ自体はまだ割り当て解除されていない可能性があります。しかし、あなたはweak varテストをView Controller自体で使うことができます。

class BasicViewController: UIViewController { 
    // this is intentionally blank 
} 

ビューコントローラはビ​​ューをロードした後、そのXCTAssertNilテストが失敗したあなたが記述行動、マニフェストどこ私はテストを書くことができます:

class MyApp2Tests: XCTestCase { 

    func testWithoutView() { 
     var controller: BasicViewController? = BasicViewController() 
     weak var weakController = controller 
     XCTAssertNotNil(weakController) 
     controller = nil 
     XCTAssertNil(weakController)   // this succeeds 
    } 

    func testWithView() { 
     var controller: BasicViewController? = BasicViewController() 
     weak var weakController = controller 
     XCTAssertNotNil(weakController) 
     controller?.loadViewIfNeeded() 
     controller = nil 
     XCTAssertNil(weakController)   // this fails 
    } 

} 

をしかし、私は追加autoreleasepoolこのビューコントローラを考えてみましょう

func testWithViewAndAutoreleasePool() { 
    weak var weakController: BasicViewController? 
    autoreleasepool { 
     var controller: BasicViewController? = BasicViewController() 
     weakController = controller 
     XCTAssertNotNil(weakController) 
     controller?.loadViewIfNeeded() 
     controller = nil 
    } 
    XCTAssertNil(weakController)   // this succeeds 
} 

ところで、あなたはadditionaを探している場合:明示的にプールが排出されたときに制御することが、それは予想通り働いていました●ビューコントローラの割り当てを解除するタイミングを確認した後、deinitcontroller = nilを設定した場合と同様にprintステートメントを追加すると、時刻がdeinitに変更されます。ビュー。

この現象は説明できません。 viewで何かすると、View Controllerのライフサイクルに影響するのはなぜですか?BTW、私はまたあなたの質問のように、ビューコントローラのプロパティで上記のテストを実行し、私はまったく同じ動作を見る(しかし、IMHO、それは単にビューコントローラ自体が割り当てが解除されていないためです。

少なくとも、自動解放プールのライフサイクルのタイミングは、autoreleasepoolで明示的に制御できます。

関連する問題