web-dev-qa-db-ja.com

Xcode 10-プロパティが「弱い」ため、インスタンスはすぐに割り当て解除されます

最近Xcode 10をダウンロードしましたが、weakまたはunowned変数を使用すると明らかなバグが見つかりました。問題を再現する簡単な例を作成して、人々が問題を再現できるようにしました。

class MainClass {
    weak var weakClass: SomeClass!

    init() {

        // WARNING: Instance will be immediately deallocated because property 'weakClass' is 'weak'

        self.weakClass = SomeClass()
    }
}

class SomeClass {}

エラーが言うように、weakClassが初期化され、常にnilになると、MainClassはすぐに割り当てを解除します。

Xcode 9.3で同じプレイグラウンドを開いたところ、エラーや警告なしでコードが正常に動作することを確認できます。

これはXcode 10のバグですか、それとも何かを得られませんか?存在する場合、回避策はありますか?

編集:オリジナルの例

class LoginCoordinator {

    var viewModel: LoginViewModel?
    var viewController: LoginViewController?

    init() {
        viewModel = LoginViewModel()
        viewModel?.coordinator = self
        viewController = LoginViewController(viewModel: viewModel!)
    }
}


class LoginViewModel: ViewModelDelegate {
    weak var coordinator: LoginCoordinator?
}

coordinatorLoginViewModelで常にnilです

AppDelegate.Swift

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?

    func setupView() {
        let coordinator = LoginCoordinator()
        let navigationController = UINavigationController(rootViewController: coordinator.create)

        navigationController.isNavigationBarHidden = true
        navigationController.navigationBar.isTranslucent = false

        window = UIWindow(frame: UIScreen.main.bounds)
        window?.rootViewController = navigationController
        window?.makeKeyAndVisible()
        window?.layer.cornerRadius = 6
        window?.layer.masksToBounds = true
    }

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        setupView()
        return true
    }
11
Nader Besada

これを理解するには、ARCの概念を知っている必要があります。 ARC概念は自動参照カウントを意味します。ARCは、割り当てられたメモリが何らかの変数によって強く参照されている限り、メモリに何かを保持します。 it(ARC)が割り当てられたメモリに強い参照を持たないことを発見した場合、それは割り当てを解除します。したがって、警告weakClassすぐにdeallocates一度MainClassが初期化され、常にnilです。強力なリファレンスがないため、疑問点をコメントしてください。

保持サイクル作成の以下の1つの例:

class A {
var classBObject: B?

  init() {
     classBObject = B()
     classBObject.classAObject = self // Creates a retain cycle
 }
}

class B {
   var classAObject: A? // Strong(by default all are strong) variable create retain cycle
}

したがって、class B私たちがweak var classAObject保持サイクルは発生しません。

8
vivekDas

これがweakの目的です。 Swiftはメモリを管理するために参照カウントを使用します。強いポインタはポイントされたオブジェクトの参照カウントを1増やします。弱いポインタは参照カウントを増やしません。参照カウントが0のオブジェクトは割り当て解除されます。

SomeClassのインスタンスは弱いポインターによってのみポイントされているため、その参照カウントは0です。その結果、すぐに割り当てが解除されます。

弱いは、保持サイクルを回避するのに役立ちます。たとえば、クロージャのエスケープや委任デザインパターンなどです。

4
ukim

問題は、「その参照は他の場所で強く参照されていますか?その場合、割り当ては解除されません」です。

Appleの警告メッセージは誤解を招くものだと提案します。含まれているオブジェクトの割り当てが解除されたとき、またはそのオブジェクトへの他の強い参照が割り当て解除されたときに、すぐに割り当てが解除されると述べるべきだと思います。

その理由は次のとおりです。

View Controllerのインスタンスでこの警告が表示され、弱い変数はすぐに割り当て解除されません。 View Controllerが表示され、弱い変数がインスタンス化され、待機し、ブレークポイントとyupにヒットするボタンをクリックします。弱い変数はまだnilではありません。しかし、View Controllerが消えて割り当てが解除されると、弱いvar isが直ちに割り当て解除されます。

しかし、なぜ?さて、変数への弱い参照を持つコードの一部が登場する頃には、他のコードには既に3の保持カウントがあり、たとえ弱いとしてもcan'tはすぐに破棄されます。

これはpo myObject.retainCountで確認できます。 notは正確であることが保証されていますが、アイデアを与えてくれます。オブジェクトのretaincountが1を超えており、他のどこかに強くリンクされている場合(コードにコメントを入れて、強く参照されている場所を示してください)、weakは機能します。コンパイラの警告を回避するには、オブジェクトを直接参照せず、他のオブジェクトの強参照を参照してください。

だから、Appleは間違いを招くのでこの警告を言い換える必要があると思う。

0
Alex Zavatone