[RxSwift] ARC, ๊ฐ•ํ•œ ์ฐธ์กฐ strong, ์•ฝํ•œ ์ฐธ์กฐ weak, ๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ ๋ฌธ์ œ
iOS/Swift

[RxSwift] ARC, ๊ฐ•ํ•œ ์ฐธ์กฐ strong, ์•ฝํ•œ ์ฐธ์กฐ weak, ๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ ๋ฌธ์ œ

Struct vs Class

Struct ํƒ€์ž…๊ณผ Class ํƒ€์ž…์„ ๋น„๊ตํ•  ๋•Œ ๊ฐ€์žฅ ๋งŽ์ด ํ•˜๋Š” ๋ง โ†’ Struct๋Š” ๊ฐ’ ํƒ€์ž…, Class๋Š” ์ฐธ์กฐ ํƒ€์ž…!

  • ๊ฐ’ ํƒ€์ž…: ์ „๋‹ฌํ•  ๋•Œ๋งˆ๋‹ค ๊ฐ’์„ ๋ณต์‚ฌํ•ด์„œ ์ „๋‹ฌ
  • ์ฐธ์กฐ ํƒ€์ž…: ํ•˜๋‚˜์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์ ‘๊ทผ
    • ์ธ์Šคํ„ด์Šค๊ฐ€ ์ ์ ˆํ•œ ์‹œ์ ์— ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ์•Š์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ์ž์›์„ ๋‚ญ๋น„ํ•˜๊ฒŒ ๋จ.

โ†’ ์Šค์œ„ํ”„ํŠธ์—์„œ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ์„ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ARC๋ฅผ ์‚ฌ์šฉ!

ARC์˜ ์ž‘๋™ ๊ทœ์น™์„ ๋ชจ๋ฅด๊ณ  ์‚ฌ์šฉํ•˜๋ฉด ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์˜์›ํžˆ ํ•ด์ œ๋˜์ง€ ์•Š์„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—... ARC์— ๋Œ€ํ•ด ์•Œ์•„์•ผ ํ•œ๋‹ค.

 

ARC


* ์ž๋™ ์ฐธ์กฐ ์นด์šดํŒ…, Automatic Reference Counting => ์ž๋™์œผ๋กœ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๊ด€๋ฆฌํ•ด ์ฃผ๋Š” ๋ฐฉ์‹

* ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์€ ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ์‹œํ‚ด

 -> ๋” ์ด์ƒ ํ•„์š”ํ•˜์ง€ ์•Š์€ ํด๋ž˜์Šค๋ฅผ ํŒ๋‹จํ•˜๊ธฐ ์œ„ํ•ด ์ฐธ์กฐ ํšŸ์ˆ˜๋ฅผ ์นด์šดํŠธ!

 

* RC(Reference Counting)๊ฐ€ 0์ด ๋˜๋Š” ์ˆœ๊ฐ„ ์ธ์Šคํ„ด์Šค๋Š” ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋จ

 

* ์ธ์Šคํ„ด์Šค๊ฐ€ ๊ณ„์† ๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์•„ ์žˆ์–ด์•ผ ํ•  ๋ฌด์–ธ๊ฐ€ ๋ช…๋ถ„์ด ํ•„์š”ํ•˜๋‹ค! โ†’ ๊ฐ•ํ•œ(Strong) ์ฐธ์กฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ RC๋ฅผ 1 ์ฆ๊ฐ€์‹œํ‚ด

 

๊ฐ•ํ•œ ์ฐธ์กฐ


ํด๋ž˜์Šค์˜ ํ”„๋กœํผํ‹ฐ ๋“ฑ์„ ์„ ์–ธํ•  ๋•Œ ๋”ฑํžˆ ๋ฌด์—‡์ธ๊ฐ€๋ฅผ ๋ช…์‹œํ•˜์ง€ ์•Š์œผ๋ฉด ๊ธฐ๋ณธ์œผ๋กœ ๊ฐ•ํ•œ ์ฐธ์กฐ

// ์ด ์ฝ”๋“œ์—์„œ ๋งํ•˜๋Š” RC(Reference Counting)๋Š” Person ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค RC!!!
class Person {
	let name: String
		
	init(name: String) {
		self.name = name
	}
}

var reference1: Person?
var reference2: Person?
var reference3: Person?

reference1 = Person(name: "JUNGBIN") // RC = 1
reference2 = reference1 // RC = 2
reference3 = reference1 // RC = 3

reference3 = nil // RC = 2
reference2 = nil // RC = 1
reference1 = nil // RC = 0 -> ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋จ!!!!

 

๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ ๋ฌธ์ œ

* ๋‘ ์ธ์Šคํ„ด์Šค๊ฐ€ ์„œ๋กœ๋ฅผ ์ฐธ์กฐํ•˜๋Š” ์ƒํ™ฉ์—์„œ ๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ

class Person {
	let name: String
		
	init(name: String) {
		self.name = name
    }
		
	var car: Car?
}

class Car {
	let name: String

	init(name: String) {
		self.name = name
	}

	var owner: Person?
}

var jungbin: Person? = Person(name: "JUNGBIN") // Person RC = 1
var myCar: Car? = Car(name: "BoongBoong") // Car RC = 1

myCar?.owner = jungbin // Person RC = 2
jungbin?.car = myCar // Car RC = 2

jungbin = nil // Person RC = 1
myCar = nil // Car RC = 1

* ์œ„ ์ฝ”๋“œ์—์„œ, jungbin์— nil์„ ํ• ๋‹นํ–ˆ์„ ๋•Œ Person RC = 1์ด ๋จ. jungbin์€ ์ด์ œ nil์ด์ง€๋งŒ, myCar.owner๋ฅผ ํ†ตํ•ด ์•„์ง Person ์ธ์Šคํ„ด์Šค์— ์ฐธ์กฐํ•  ์ˆ˜ ์žˆ์Œ. Person ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์‚ด์•„ ์žˆ๊ณ , Person ์ธ์Šคํ„ด์Šค์— ์ฐธ์กฐํ•  ๋ฐฉ๋ฒ•๋„ ๋‚จ์•„ ์žˆ๋Š” ์ƒํ™ฉ! ํ•˜์ง€๋งŒ ๋‹ค์Œ์— myCar์— nil์„ ํ• ๋‹นํ–ˆ์„ ๋•Œ, myCar๊ฐ€ ์ฐธ์กฐํ•˜๋˜ ์ธ์Šคํ„ด์Šค์˜ RC๋Š” ํ•˜๋‚˜ ๊ฐ์†Œํ•˜์—ฌ 1์ด ๋˜์—ˆ์Œ. ๊ทผ๋ฐ ์ด์ œ myCar.owner๋กœ Person ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๊ณ , myCar๋„ nil์ด๋ผ์„œ Car ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•จ. ์ธ์Šคํ„ด์Šค์— ์ ‘๊ทผํ•  ๋ฐฉ๋ฒ•์€ ์‚ฌ๋ผ์กŒ๋Š”๋ฐ, ์ •์ž‘ ์ธ์Šคํ„ด์Šค๋“ค์€ ๋ฉ”๋ชจ๋ฆฌ์— ๋‚จ์•„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—(RC = 1) ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ๋ฐœ์ƒ!

 

* ์•„๋ž˜ ๊ทธ๋ฆผ์—์„œ ViewController๊ฐ€ ํ™”๋ฉด์—์„œ pop ๋˜๊ณ  ์ด์ œ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋ฐ๋„ ๋ถˆ๊ตฌํ•˜๊ณ  3๋ฒˆ์˜ self.์–ด์ฉŒ๊ณ ์ €์ฉŒ๊ณ  ์ฝ”๋“œ์— ์˜ํ•ด RC ์นด์šดํŠธ๊ฐ€ ํ•œ ๋ฒˆ ์ฆ๊ฐ€๋˜์—ˆ๊ธฐ ๋•Œ๋ฌธ์— 4๋ฒˆ์—์„œ RC = 1์ด ๋จ. ViewController์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋˜์ง€ ์•Š์Œ!!!! โ†’ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜(Memory Leak)

 

์•ฝํ•œ ์ฐธ์กฐ


* ๊ฐ•ํ•œ ์ฐธ์กฐ์™€ ๋‹ฌ๋ฆฌ, ์ž์‹ ์ด ์ฐธ์กฐํ•˜๋Š” ์ธ์Šคํ„ด์Šค์˜ ์ฐธ์กฐ ํšŸ์ˆ˜๋ฅผ ์ฆ๊ฐ€์‹œํ‚ค์ง€ ์•Š์Œ

* ์ฐธ์กฐํ•˜๋Š” ํƒ€์ž…์˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์„ ์–ธํ•˜๋Š” ๋ฌธ์žฅ ์•ž์— weak๋ฅผ ์จ ์ฃผ๋ฉด ๊ทธ ํ”„๋กœํผํ‹ฐ๋Š” ์ธ์Šคํ„ด์Šค๋ฅผ ์•ฝํ•œ ์ฐธ์กฐ!

* ์•„๋ž˜ ์ฝ”๋“œ๋Š” ์•ฝํ•œ ์ฐธ์กฐ๋ฅผ ํ†ตํ•ด ๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ์ฝ”๋“œ

class Person {
	let name: String
		
	init(name: String) {
		self.name = name
	}
	
	var car: Car?
}

class Car {
	let name: String

	init(name: String) {
		self.name = name
	}

	weak var owner: Person?
}

var jungbin: Person? = Person(name: "JUNGBIN") // Person RC = 1
var myCar: Car? = Car(name: "BoongBoong") // Car RC = 1

myCar?.owner = jungbin // Person RC = 1 ์•ฝํ•œ ์ฐธ์กฐ!
jungbin?.car = myCar // Car RC = 2 ๊ฐ•ํ•œ ์ฐธ์กฐ!

jungbin = nil // Person RC = 0, Car RC = 1
print(myCar?.owner) // Person์˜ ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์—†๊ธฐ ๋•Œ๋ฌธ์— nil(์•ฝํ•œ ์ฐธ์กฐ ํ•ด์„œ ๊ทธ๋Ÿผ)

myCar = nil // Car RC = 0

 

* ์•„๋ž˜์—์„œ ์„ธ ๋ฒˆ์งธ ๋ผ์ธ์„ ๋ณด๋ฉด... ์ธ์Šคํ„ด์Šค๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œ๋  ๋•Œ, ์ž์‹ ์˜ ํ”„๋กœํผํ‹ฐ(car)๊ฐ€ ๊ฐ•ํ•œ ์ฐธ์กฐ๋ฅผ ํ•˜๋˜ ์ธ์Šคํ„ด์Šค(Car ์ธ์Šคํ„ด์Šค)์˜ RC๋ฅผ 1 ๊ฐ์†Œ์‹œํ‚จ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ์Œ

 

๊ฐ•ํ•œ ์ฐธ์กฐ ์ˆœํ™˜ ๋ฌธ์ œ๋ฅผ ๋ฉ‹์ง€๊ฒŒ ํ•ด๊ฒฐํ•˜์˜€์Šต๋‹ˆ๋‹ค~~~