无主变量和异步函数
Unowned variables and async functions
我有一个 class 有一个无主变量。像这样:
class Student {
unowned var school: School
init(_ school: School) {
self.school = school
}
}
现在假设我在 class 中有一个转义异步函数:
class Student {
unowned var school: School
init(_ school: School) {
self.school = school
}
// When this function is first called
// I can guarantee school has not been de-initialized
func reportAttendance(completionHandler: @escaping (() -> Void)) {
database.studentDidReportAttendance(student: self) {
// I cannot guarantee school has not been deinitialized
// when this callback function returns!
school.updateAttendance()
completionHandler()
}
}
}
我的问题是我可以保证当reportAttendance()
被调用时,那个学校没有被反初始化,但是在数据库响应的时间里,我不能保证学校赢了' 不被初始化。因此,如果是,那么当异步块 returns 并尝试访问学校时,我会收到 运行 时间错误。
我的问题是如何在第一次调用该函数时创建对学校的临时强引用,然后在我能够安全地 运行 updateAttendance
上学后释放它?
谢谢
似乎是一个 x-y 问题。如果一个学生的 school
可以消失而这个学生仍然存在,那就是对 unowned
的错误使用。说unowned
的前提是那肯定是绝对不可能的。
您可以在函数内部创建一个局部变量来保持强引用;看这个测试:
class School {
deinit {
print ("School.deinit")
}
}
class Student {
unowned var school:School
init(_ school: School) {
self.school = school
}
func printSchool() -> (() -> Void) {
let strongSchool = self.school
return { print ("I'm going to \(strongSchool)") }
}
}
if (1==1) {
var s:School? = School()
let student = Student(s!)
let p = student.printSchool()
s = nil
p() // Won't crash
}
没有 strongSchool
,代码段会崩溃。
关键是我们在闭包外创建了一个强引用——此时你保证它仍然存在——然后在闭包内引用它。这样,我们
- 不捕获
student
/self
,只捕获 school
- 避免循环引用,以防
database
可以被学生强烈访问并将其自身保持为 属性 的闭包(因为 self
-> database
-> closure
-> self
) 并且只要 school
不也引用数据库(好吧,写起来比想起来更复杂)
但是正如@matt 所说,unowned
是非常危险的,应该首选 weak
,除了一些不常见的情况,在这些情况下,您有无数个无主对象,这会导致大量的内务管理开销.
我有一个 class 有一个无主变量。像这样:
class Student {
unowned var school: School
init(_ school: School) {
self.school = school
}
}
现在假设我在 class 中有一个转义异步函数:
class Student {
unowned var school: School
init(_ school: School) {
self.school = school
}
// When this function is first called
// I can guarantee school has not been de-initialized
func reportAttendance(completionHandler: @escaping (() -> Void)) {
database.studentDidReportAttendance(student: self) {
// I cannot guarantee school has not been deinitialized
// when this callback function returns!
school.updateAttendance()
completionHandler()
}
}
}
我的问题是我可以保证当reportAttendance()
被调用时,那个学校没有被反初始化,但是在数据库响应的时间里,我不能保证学校赢了' 不被初始化。因此,如果是,那么当异步块 returns 并尝试访问学校时,我会收到 运行 时间错误。
我的问题是如何在第一次调用该函数时创建对学校的临时强引用,然后在我能够安全地 运行 updateAttendance
上学后释放它?
谢谢
似乎是一个 x-y 问题。如果一个学生的 school
可以消失而这个学生仍然存在,那就是对 unowned
的错误使用。说unowned
的前提是那肯定是绝对不可能的。
您可以在函数内部创建一个局部变量来保持强引用;看这个测试:
class School {
deinit {
print ("School.deinit")
}
}
class Student {
unowned var school:School
init(_ school: School) {
self.school = school
}
func printSchool() -> (() -> Void) {
let strongSchool = self.school
return { print ("I'm going to \(strongSchool)") }
}
}
if (1==1) {
var s:School? = School()
let student = Student(s!)
let p = student.printSchool()
s = nil
p() // Won't crash
}
没有 strongSchool
,代码段会崩溃。
关键是我们在闭包外创建了一个强引用——此时你保证它仍然存在——然后在闭包内引用它。这样,我们
- 不捕获
student
/self
,只捕获school
- 避免循环引用,以防
database
可以被学生强烈访问并将其自身保持为 属性 的闭包(因为self
->database
->closure
->self
) 并且只要school
不也引用数据库(好吧,写起来比想起来更复杂)
但是正如@matt 所说,unowned
是非常危险的,应该首选 weak
,除了一些不常见的情况,在这些情况下,您有无数个无主对象,这会导致大量的内务管理开销.