我最近下载了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 {}
正如错误所说,一旦初始化MainClass
weakClass
立即解除分配,并且始终为零。
我已经用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?
}
coordinator
在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
}
要理解这一点,您必须了解ARC
的概念。ARC
概念是自动引用计数意味着只要分配的内存被某个变量强引用ARC
就会在内存中保留某些内容。如果它(ARC(发现一些分配的内存没有任何强引用,它将解除分配它。因此,一旦初始化MainClass
,警告weakClass
立即deallocates
,并且始终为 nil。因为它没有任何强有力的参考。如有疑问,请发表评论。
下面是一个用于创建保留周期的示例:
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
保留周期就不会发生。
这就是weak
的目的。Swift 使用引用计数来管理内存。强指针将指向对象的引用计数增加 1,弱指针不会增加引用计数。引用计数为 0 的对象将被解除分配。
您的实例SomeClass
仅由弱指针指向,因此其引用计数为 0。因此,它立即被解除分配。
弱对于避免保留周期很有用。例如,在转义闭包和委派设计模式中。
问题是,"该引用是否在其他地方被强烈引用? 如果是这样,它将不会被解除分配。
我认为苹果的警告信息具有误导性。 我认为它应该声明,当它的包含对象被释放或当对它的其他强引用被解除分配时,它将立即被释放。
原因如下。
我们在视图控制器中的实例上有此警告,并且弱变量不会立即释放。视图控制器出现,弱变量被实例化,我们等待,单击一个命中断点的按钮,是的,弱变量仍然不是零。然而,当视图控制器消失并被解除分配时,弱变量会立即释放。
但是为什么?好吧,当我们来到代码中对变量的弱引用部分时,其他代码已经导致该变量的保留计数为 3。这意味着即使它很弱,can't
立即被解雇。
您可以使用po myObject.retainCount
检查这一点。 它不能保证准确,但它会给你一个想法。 如果对象的 retainCount> 1 并且它在其他地方有强链接(请在代码中放置注释以指示它被强引用的位置(,则弱将起作用。 若要避免编译器警告,请不要直接引用该对象,而是引用另一个对象的强引用。
所以,我认为苹果需要改写这个警告,因为它肯定是误导性的。
此外,鉴于 Swift 属性没有相应的实例变量,当您为弱属性赋值时,它会立即被解除分配,这是有道理的。我在这里遇到了类似的问题,我的场景委托要求这个应用程序协调员的rootViewController:
class AppCoordinator {
private weak var navigationController : UINavigationController!
var rootViewController : UIViewController {
navigationController = UINavigationController()
return navigationController // <-- here the app crashes: Fatal error: Unexpectedly found nil while implicitly unwrapping an Optional value
}
}