Weak Self in SwiftUI

Updated:

weak self in SwiftUI

Often times in your app when users moving around the app behind the scenes the app is actually de-initializing screens and views that the user is no longer using so this is efficient so if they go to the screen and then press it back that screen might get de-initialized so any objects that were created on that screen would then be removed from our account.

You basically are creating a strong reference to that screen or that object and the solution is to basically create a weak reference instead of a strong reference that’s kind of what weak self is.

When we have these functions that are going to the Internet and then coming back it becomes very important to understand these strong and weak references you’re probably going to want to use a weak self a lot of times

import SwiftUI

struct WeakSelfBootCamp: View {
// MARK: -  PROPERTY

// MARK: -  BODY
var body: some View {
  NavigationView {
    NavigationLink("Navigate", destination: WeakSelfSecondScreen())
      .navigationTitle("Scrren 1")
  } //: NAVIGATION
}
}

// MARK: -  SECOND SCREEN
struct WeakSelfSecondScreen: View {
  // MARK: -  PROPERTY
@StateObject var vm = WeakSelfSecondScreenViewModel()

var body: some View {
  VStack {
    Text("Second View")
      .font(.largeTitle)
    .foregroundColor(.red)

    if let data = vm.data {
      Text(data)
    }
  } //: VSTACK
}
}

// MARK: -  SECOND SCREEN VIEWMODEL
class WeakSelfSecondScreenViewModel: ObservableObject {
// MARK: -  PROPERTY
@Published var data: String? = nil
// MARK: -  INIT
init() {
  print("INITIALZE NOW")
  getData()
}
deinit {
  print("DE-INITIALZE NOW")
}

// MARK: -  FUNCTION
func getData() {
  data = "NEW DATA!!"
}
}

When you click Navigation Button you can see the print log initialize and de-initialized ono by one

image

Strong self example

// MARK: -  SECOND SCREEN VIEWMODEL
class WeakSelfSecondScreenViewModel: ObservableObject {
// MARK: -  PROPERTY
@Published var data: String? = nil
// MARK: -  INIT
init() {
print("INITIALZE NOW")
let currentCount = UserDefaults.standard.integer(forKey: "count")
UserDefaults.standard.set(currentCount + 1, forKey: "count")
getData()
}
deinit {
print("DE-INITIALZE NOW")
let currentCount = UserDefaults.standard.integer(forKey: "count")
UserDefaults.standard.set(currentCount - 1, forKey: "count")
}

// MARK: -  FUNCTION
func getData() {

DispatchQueue.global().async {
  // just using self = Strong reference : while these tasks are running this class absolutely need to stay alive
  // because we need that self when we come back
  // but if you were downloading like a lof of data from the Internet the code in this async task
  // might tak s couple seconds it could take like 10 seconds
  // and during that time the user could be doing something on the app
  // if you want to leave second screen need any more to use weak self to remove reference when you
  // leave the second screen and no longer data anymore
  // self.data = "NEW DATA!!"

  // Delay
  // In case of very long after background tasks not called de-initialized was never called
  // because of delay "NEW DATA" after 500 seconds problem is this is Strong reference
  // This is not a efficient
  DispatchQueue.main.asyncAfter(deadline: .now() + 500) {
    self.data = "NEW DATA!!"
  }
}
}
}

스크린샷 image

Weak self example

// MARK: -  FUNCTION
func getData() {

  // The solution here is basically instead of calling itself with this strong reference which means
  // absolutely need this class to stay alive to add weak self
  // weak self just makes this self instead of being a strong reference it turns into a weak reference
  // And self is now optional so we will have reference to this data that we can update
  // but we're telling the code here that we don't absolutely need this class to stay alive
  // if this class for whatever reason gets de-initialized it's okay and we can just ignore
  // whatever these calls are
  DispatchQueue.global().async {
    // Delay
    DispatchQueue.main.asyncAfter(deadline: .now() + 500) { [weak self] in
      self?.data = "NEW DATA!!"
    }
  }
}
}

스크린샷 image

Generally, When you have these long tasks that you’re like downloading data fro the user it’s very important to add this weak self because if you’re downloading data for the second screen and then the user goes away to another screen.

You don’t really need that first screen to stay alive anymore and if you kept that screen alive it would stay in memory it would start to slow down your application and it just wouldn’t be very efficient


🗃 Reference

SwiftUI Thinking - https://www.youtube.com/watch?v=jEpg2SYvVV8&list=PLwvDm4VfkdpiagxAXCT33Rkwnc5IVhTar&index=19

Categories:

Updated:

Leave a comment