Is it safe to force unwrap variables that have been optionally accessed in the same line of code?

后端 未结 5 939
无人及你
无人及你 2020-12-14 05:52
someFunction(completion: { [weak self] in
    self?.variable = self!.otherVariable
})

Is this always safe? I access the optional <

5条回答
  •  一整个雨季
    2020-12-14 06:41

    BEFORE CORRECTION:

    I think others have answered the details of your question far better that I could.

    But aside from learning. If you actually want your code to reliably work then its best to do as such:

    someFunction(completion: { [weak self] in
        guard let _ = self else{
            print("self was nil. End of discussion")
            return
        }
        print("we now have safely 'captured' a self, no need to worry about this issue")
        self?.variable = self!.otherVariable
        self!.someOthervariable = self!.otherVariable
    }
    

    AFTER CORRECTION.

    Thanks to MartinR's explanation below I learnt a great deal.

    Reading from this great post on closure capturing. I slavishly thought whenever you see something in brackets [] it means it's captured and its value doesn't change. But the only thing we're doing in the brackets is that we are weak-ifying it and making it known to ourselves that it's value could become nil. Had we done something like [x = self] we would have successfully captured it but then still we'd have the problem of holding a strong pointer to self itself and be creating a memory cycle. (It's interesting in the sense it's a very thin line from going to creating a memory cycle to creating a crash due to the value being deallocated because you weak-ified it).

    So to conclude:

    1. [capturedSelf = self]

      creates memory cycle. Not good!

    2. [weak self] 
      in guard let _ = self else{
      return
      } 
      

      (can lead to crash if you force self unwrap afterwards) the guard let is it utterly useless. Because the very next line, still self can become nil. Not good!

    3. [weak self] 
      self?.method1()
      

      (can lead to crash if you force self unwrap afterwards. Would go through if self is non-nil. Would fail safely if self is nil.) This is what most likely what you want. This is Good!

    4. [weak self] in 
      guard let strongSelf = self else{ 
      return
      } 
      

      Will fail safely if self was deallocated or proceed if not nil. But it kinda defeats the purpose, because you shouldn't need to communicate with self when it removed it's own reference. I can't think of a good use case for this. This is likely useless!

提交回复
热议问题