强引用是指在Swift中,通过在变量或常量前添加var
和let
关键字来进行赋值的方式。它随时都会持有对象的引用,并且只要有强引用存在,它所对应的对象就不会释放。以下是强引用的作用及使用攻略:
强引用的作用
1. 防止对象被提前释放
强引用保证了对象在被其它代码使用之前不会被提前释放。如果当前代码中使用了一个对象,而该对象又没有强引用一直持有,那么该对象就会被ARC系统判断为不再被需要,从而被释放掉。这将导致其它代码因为使用了这个对象而发生意外的运行时错误。有了强引用,即使当前作用域结束了,该对象仍然会被其它强引用所持有,直到所有强引用都被释放为止。
2. 构建对象引用图的主支干道
对于一个复杂的对象引用图而言,强引用通常是构建主支干道的主要手段。我们可以通过在组件之间建立强引用,来定义对象之间的关系,并确保不会出现循环引用的情况。
强引用的使用攻略
强引用的使用攻略如下:
1. 在必须的情况下使用强引用
避免过度或不正确地使用强引用。我们应该只在必须的情况下使用强引用,以便避免可能的循环引用,或者过早地释放对象。
2. 在适当的时候使用弱引用和无主引用
当两个对象之间形成一个双向的引用时,我们应该使用弱引用或者无主引用来避免循环引用。使用弱引用可以在对象不再需要时自动释放引用,而使用无主引用则可以在我们需要时手动释放引用。
3. 在释放对象时解除强引用
当我们使用完一个对象时,应该尽早地释放对该对象的强引用,以便给ARC系统知道这个对象可以被释放。
以下是两个示例说明:
示例1
class Person {
var name: String
var pet: Pet?
init(name: String) {
self.name = name
}
func introducePet() {
if let pet = pet {
print("\(name) has a pet named \(pet.name)")
} else {
print("\(name) doesn't have any pets")
}
}
deinit {
print("\(name) is being deinitialized")
}
}
class Pet {
var name: String
var owner: Person?
init(name: String) {
self.name = name
}
deinit {
print("\(name) is being deinitialized")
}
}
var john: Person?
var dog: Pet?
john = Person(name: "John Doe")
dog = Pet(name: "Rover")
john?.pet = dog
dog?.owner = john
john = nil
dog = nil // prints out "Rover is being deinitialized"
在这个示例中,Person
和Pet
之间形成了一种双向引用关系。由于Person
和Pet
都使用了强引用,这个双向引用将导致它们之间的引用关系不被释放,从而形成循环引用。为了避免这种情况,我们应该将其中一个引用设置为弱引用或者无主引用,以便在适当的时候释放它。
示例2
class ViewController: UIViewController {
var networkManager: NetworkManager?
var user: User?
override func viewDidLoad() {
super.viewDidLoad()
user = User(login: "example", password: "password")
networkManager?.login(user: user!)
}
func loginStatusChanged(isLoggedIn: Bool) {
if isLoggedIn {
// do something
} else {
// do something else
}
}
deinit {
print("Deallocating ViewController")
}
}
class NetworkManager {
var viewController: ViewController?
func login(user: User) {
// perform login request
viewController?.loginStatusChanged(isLoggedIn: true)
}
deinit {
print("Deallocating NetworkManager")
}
}
class User {
var login: String
var password: String
init(login: String, password: String) {
self.login = login
self.password = password
}
deinit {
print("Deallocating User")
}
}
var viewController: ViewController?
var networkManager: NetworkManager?
viewController = ViewController()
networkManager = NetworkManager()
viewController?.networkManager = networkManager
networkManager?.viewController = viewController
viewController = nil
networkManager = nil // prints out "Deallocating NetworkManager"
在这个示例中,ViewController
和NetworkManager
之间形成了一种双向引用关系,其中NetworkManager
强引用了ViewController
,而ViewController
强引用了自定义的User
实例。这个双向引用将导致它们之间的引用关系不被释放,从而形成循环引用。为了避免这种情况,我们可以在适当的时候解除强引用,以便在对象不再需要时释放它们。在这个例子中,我们可以在viewDidLoad()
中手动调用login()
方法,以避免在对象被释放之前触发它的方法。