20. Memory, Value Type and Reference Type

Kang.__.Mingu·2021년 7월 31일
0

1. Study Swift

목록 보기
20/25

메모리가 값을 저장하는 방법을 공부, 값 형식과 참조 형식의 차이점을 비교한다.

Memory Basics

메모리에 대한 기초적인 내용 공부
메모리 관련 자료

Value Type vs Reference Type

값 형식과 참조 형식이 메모리에 저장되는 방식에 대해 공부

struct SizeValue {
   var width = 0.0
   var height = 0.0
}

var value = SizeValue()


var value2 = value
value2.width = 1.0
value2.height = 2.0

value
value2


class SizeObject {
   var width = 0.0
   var height = 0.0
}

var object = SizeObject()

var object2 = object

object2.width = 1.0
object2.height = 2.0

object
object2



let v = SizeValue()


let o = SizeObject()
o.width = 1.0
o.height = 2.0

ARC(Automatic Reference Counting)

Swift의 메모리 관리 모델인 ARC에 대해 공부

  • class 인스턴스 메모리 관리
  • String Reference
  • 소유관을 가지면 1 증가 소유권 포기하면 1 감소 0이면 삭제
class Person {
   var name = "John Doe"
   
   deinit {
      print("person deinit")
   }
}

var person1: Person?
var person2: Person?
var person3: Person?

person1 = Person()
person2 = person1
person3 = person1

person1 = nil
person2 = nil
person3 = nil

Strong Reference Cycle

강한 참조 사이클이 발생하는 원인과 해결 방법에 대해 공부

Strong Reference Cycle

강한 참조 사이클

class Person {
   var name = "John Doe"
   var car: Car?
   
   deinit {
      print("person deinit")
   }
}

class Car {
   var model: String
   var lessee: Person?
   
   init(model: String) {
      self.model = model
   }
   
   deinit {
      print("car deinit")
   }
}

var person: Person? = Person()
var rentedCar: Car? = Car(model: "Porsche")

person?.car = rentedCar
rentedCar?.lessee = person

person = nil
rentedCar = nil


person = nil
rentedCar = nil

Weak Reference

weak var name: Type?

약한 참조 사이클
weak 키워드 추가

class Person {
   var name = "John Doe"
   var car: Car?
   
   deinit {
      print("person deinit")
   }
}

class Car {
   var model: String
   weak var lessee: Person?     // weak 키워드 추가(참조하지만 소유는 안함)
   
   init(model: String) {
      self.model = model
   }
   
   deinit {
      print("car deinit")
   }
}

var person: Person? = Person()
var rentedCar: Car? = Car(model: "Porsche")

person?.car = rentedCar
rentedCar?.lessee = person

person = nil
rentedCar = nil

Unowned Reference

unowned var name: Type

비소유 참조
Non 옵셔널 형식
unowned 키워드

class Person {
   var name = "John Doe"
   var car: Car?

   deinit {
      print("person deinit")
   }
}

class Car {
   var model: String
   unowned var lessee: Person           // unowned 키워드

   init(model: String, lessee: Person) {
      self.model = model
      self.lessee = lessee
   }

   deinit {
      print("car deinit")
   }
}

var person: Person? = Person()
var rentedCar: Car? = Car(model: "Porsche", lessee: person!)

person?.car = rentedCar

person = nil
rentedCar = nil

Unowned Optional Reference

Unowned Reference를 옵셔널로 선언하는 문법에 대해 공부

unowned var name: Type?
class Person {
   var name = "John Doe"
   var car: Car?

   deinit {
      print("person deinit")
   }
}

class Car {
   var model: String
   unowned var lessee: Person?

   init(model: String, lessee: Person) {
      self.model = model
      self.lessee = lessee
   }

   deinit {
      print("car deinit")
   }
}

var person: Person? = Person()
var rentedCar: Car? = Car(model: "Porsche", lessee: person!)

person?.car = rentedCar

person = nil
rentedCar?.lessee = nil

rentedCar?.lessee

rentedCar = nil

// Strong 레퍼런스를 해결해야하는 상황에서 타입을 옵셔널로 사용해야한다면 weak 레퍼런스를 사용하고
// 타입을 Non옵셔널로 선언해야하는 경우에만 Unowned 레퍼런스 사용

Closure Capture List

Closure Capture List를 통해 클로저에서 발생하는 강한 참조 사이클을 해결하는 방법에 대해 공부

class Car {
   var totalDrivingDistance = 0.0
   var totalUsedGas = 0.0
   
   lazy var gasMileage: () -> Double = { [unowned self] in       // 지연저장 속성
        return self.totalDrivingDistance / self.totalUsedGas
   }
   
   func drive() {
      self.totalDrivingDistance = 1200.0
      self.totalUsedGas = 73.0
   }
   
   deinit {     // 인스턴스 해제시 호출
      print("car deinit")
   }
}


var myCar: Car? = Car()
myCar?.drive()

myCar?.gasMileage() // 클로저가 self를 호출

myCar = nil
{ [list]  (parameters) -> ReturnType in
   Code
}

{ [list] in 
   Code
}

Value Type

{ [valueName] in
   Code
}

가평식에는 대상의 이름만 캡쳐

var a = 0
var b = 0
let c = { [a] in print(a, b) }

a = 1
b = 2
c()

Reference Type

{ [weak instanceName, unowned instanceName] in
   statements
}
  • 참조형식을 캡쳐할 때 대상이름 앞에 weak 키워드나, unowned 키워드 사용
  • 비소유 참조로 캡쳐한 대상은 클로저 대상이 종료되기 전에 해제 될 수 있다.
  • 해제된 대상에 접근할 경우 런타임 오류가 발생하기 때문에 조심해야한다
  • 그래서 비소유 참조는 캡쳐 생명주기가 클로저와 같거나 더 긴 경우에 주로 사용한다.

Explicit Strong Capture

클로저에 내부에서 self에 접근하는 코드를 더욱 단순하게 만들어주는 문법을 공부

클로저의 self에 더 단순하게 접근하도록 도와줌

struct PersonValue {
   let name: String = "Jane Doe"
   let age: Int = 0
   
   func doSomething() {
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            print(name, age)
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            print(self.name, self.age)
        }
    DispatchQueue.main.asyncAfter(deadline: .now() + 1) { [self] in
            print(name, age)
        }
   }
}

class PersonObject {
   let name: String = "John Doe"
   let age: Int = 0
   
   func doSomething() {
      DispatchQueue.main.asyncAfter(deadline: .now() + 1) { 
        print(self.name, self.age)
      }
   }
}
profile
최선을 다해 꾸준히 노력하는 개발자 망고입니당 :D

0개의 댓글