J'ai récemment téléchargé Xcode 10 et j'ai remarqué un bogue apparent lors de l'utilisation de variables weak
ou unowned
. J'ai réussi à créer un exemple simple qui présente le problème afin que les gens puissent le recréer.
class MainClass {
weak var weakClass: SomeClass!
init() {
// WARNING: Instance will be immediately deallocated because property 'weakClass' is 'weak'
self.weakClass = SomeClass()
}
}
class SomeClass {}
Comme le dit l'erreur, weakClass
est désalloué immédiatement une fois que MainClass
est initialisé et est toujours nul.
J'ai ouvert le même terrain de jeu avec Xcode 9.3 et je peux confirmer que le code fonctionne correctement, sans erreur ni avertissement.
Est-ce un bug dans Xcode 10 ou est-ce que je ne reçois pas quelque chose? Si c'est le cas, existe-t-il des solutions de contournement?
EDIT: Exemple d'origine
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?
}
coordinator
est toujours nul dans LoginViewModel
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
}
Pour comprendre cela, vous devez connaître le concept de ARC
. ARC
le concept est automatique compte de référence signifie que ARC
gardera quelque chose en mémoire, tant qu'une mémoire allouée est fortement référencée par une variable. Si elle (ARC) trouve de la mémoire allouée sans référence forte, elle sera désaffectée. Ainsi, l’avertissement weakClass
immédiatement deallocates
une fois MainClass
est initialisé et est toujours nul. Parce qu'il n'y a pas de référence forte. Merci de commenter.
n exemple ci-dessous pour la création d'un cycle de conservation:
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
}
Donc, dans class B
si nous prenons weak var classAObject
conserver le cycle ne se produira pas.
C'est le but de weak
. Swift utilise le compte de références pour gérer la mémoire. Un pointeur fort augmente le compte de référence de l'objet pointé de 1, un pointeur faible n'augmente pas le compte de référence. Un objet avec un compte de référence 0 sera désalloué.
Votre instance de SomeClass
n'est pointée que par un pointeur faible. Son nombre de références est donc 0. Par conséquent, elle est désallouée immédiatement.
Faible est utile pour éviter les cycles de rétention. Par exemple, en mode échappement de fermeture et en modèle de conception de délégation.
La question est "cette référence est-elle fortement référencée ailleurs? Si oui, elle ne sera pas désallouée".
Je propose que le message d'avertissement d'Apple est trompeur. Je pense qu'il devrait indiquer qu'il sera désalloué immédiatement lorsque son objet conteneur sera désalloué ou lorsque d'autres références fortes le concernant seront libérées.
Voici pourquoi.
Nous avons cet avertissement sur une instance d'un contrôleur de vue et la variable faible n'est pas désallouée immédiatement. Le contrôleur de vue apparaît, la variable faible est instanciée, nous attendons, cliquez sur un bouton qui atteint un point d'arrêt, et oui, la variable faible n'est toujours pas nulle. Pourtant, lorsque le contrôleur de vue disparaît et est désalloué, le faible var is est immédiatement désalloué.
Mais pourquoi? Eh bien, au moment où nous arrivons à la partie de code qui a une référence faible à la variable, un autre code a déjà un nombre de conservations de 3 et même si elle est faible, elle can't
être immédiatement renvoyé.
Vous pouvez vérifier cela avec po myObject.retainCount
. C'est pas garanti d'être précis, mais cela vous donnera une idée. Si l'objet retaincount> 1 et qu'il est fortement lié ailleurs (veuillez mettre un commentaire dans votre code pour indiquer où il est fortement référencé), faiblera. Pour éviter un avertissement du compilateur, ne référencez pas directement l'objet, mais la référence forte dans l'autre objet.
Donc, je pense que Apple doit reformuler cet avertissement, car il est certainement trompeur.