Reputation: 95
So here is my code
func retrieveAndAssignHighScoreFromCloudKit() {
let high = highScore
database.fetchRecordWithID(getRecordID(high), completionHandler: { [weak self]
(record: CKRecord?, error: NSError?) in
if error != nil {
print(self!.highScore)
// blah blah blah...
}
So in the first line of this function I am able to call highScore and assign it to something else but inside the closure Xcode is forcing me to use "self!." and in doing so somehow unwraps an optional even though my calling it prior shows me that it is not nil. I am really confused and there are a ton of basic questions about unwrapping optionals as nil but none that I've found seem to pertain to this.
Thank you very much!
EDIT: Tried switching "weak" to "unowned" and I crash on the same line and get "Thread 3: EXC_BREAKPOINT" despite not having and breakpoints. This message is displayed in green on another screen and does not highlight that line
Upvotes: 2
Views: 544
Reputation: 471
You can use a strong
reference when trying to use self
like this:
func retrieveAndAssignHighScoreFromCloudKit() {
let high = highScore
database.fetchRecordWithID(getRecordID(high), completionHandler: { [weak self]
(record: CKRecord?, error: NSError?) in
if error != nil {
guard let strongSelf = self else {
return
}
print(strongSelf.highScore)
// blah blah blah...
}
}
}
Upvotes: -1
Reputation: 273987
Closures are not executed immediately.
When you pass a closure to the fetchRecordWithID
method, you are telling it to execute that code when the method finishes fetching data, which can take time.
So far so good, right?
In the closure's capture list, you tell it to capture self
as a weak
reference. What's the purpose of this? To avoid a strong reference cycle, of course. If you don't, self
holds a strong reference to the closure, and the closure holds a strong reference to self
. As a result, both the closure and self
will not be deinitialized.
A weak
reference to self
in the closure guarantees that self
is deinitialized when the strong reference to the closure is broken.
I hope I've explained this well.
So now, let's say the strong reference to the closure is broken. As I said, self
would be deinitialized as a result. After that, the thing finishes fetching data and it is now executing the completionHandler
closure! Since self
is already nil at this point, your app will crash when it reaches print(self!.highScore)
.
In other words, a weak reference to self
implies that self
can be nil. You need to unwrap it.
EDIT:
Maybe images can explain this better. (black arrows are strong references, green arrows are weak ones)
At first, it's like this:
When the strong reference is broken...
self becomes nil:
You can simply do something like this:
if let score = self?.highScore {
print(score)
// blah blah blah
} else {
// do something else, or nothing
}
Or just this:
print(self?.highScore)
Upvotes: 0