[Swift๐Ÿฆฉ] #26 ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ „์„ฑ

๋˜์ƒยท2022๋…„ 4์›” 27์ผ
0

iOS

๋ชฉ๋ก ๋ณด๊ธฐ
38/42
post-thumbnail
  • Swift ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฝ”๋“œ์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ถˆ์•ˆ์ „ํ•œ ๋™์ž‘๋“ค์„ ์ž๋™์œผ๋กœ ๋ฐฉ์ง€ํ•ด์ค€๋‹ค.
  • ๋ณ€์ˆ˜๊ฐ€ ์‚ฌ์šฉ ์ „์— ์ดˆ๊ธฐํ™” ๋˜์–ด ์žˆ๋Š”์ง€, ํ• ๋‹น ํ•ด์ œ ํ›„์—๋Š” ์ ‘๊ทผํ•˜์ง€ ์•Š์Œ.
  • ๋ฐฐ์—ด ์ธ๋ฑ์Šค ๋ฒ”์œ„๋ฅผ ๋ฒ—์–ด๋‚˜๋Š”์ง€ ...

  • ๋ฉ”๋ชจ๋ฆฌ ์œ„์น˜๋ฅผ ์ˆ˜์ •ํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ํ•ด๋‹น ๋ฉ”๋ชจ๋ฆฌ์— ๋Œ€ํ•œ ๋…์  ๊ถŒํ•œ์„ ๊ฐ€์ง€๋„๋ก ์š”๊ตฌํ•ด์„œ
  • ๋™์ผํ•œ ๋ฉ”๋ชจ๋ฆฌ ์˜์—ญ์— ๋‹ค์ค‘ ์ ‘๊ทผ์ด ์ผ์–ด๋‚˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค.
  • ํ•˜์ง€๋งŒ, ์ž ์žฌ์ ์œผ๋กœ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
    • ์ปดํŒŒ์ผ / ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ ๋ฐœ์ƒ.

1. ๋ฉ”๋ชจ๋ฆฌ์— ์ถฉ๋Œํ•˜๋Š” ์ ‘๊ทผ ์ดํ•ด

  • ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ์„ค์ •ํ•˜๊ฑฐ๋‚˜
  • ํ•จ์ˆ˜์— ์ธ์ž๋ฅผ ์ „๋‹ฌํ•˜๋Š”
  • ๋™์ž‘์„ ํ•  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ์— ์ ‘๊ทผํ•˜๊ฒŒ ๋œ๋‹ค.
var one = 1 // ์“ฐ๊ธฐ ์ ‘๊ทผ.

print("We're number \(one)!") // ์ฝ๊ธฐ ์ ‘๊ทผ.
  • ์ฝ”๋“œ์˜ ๋‹ค๋ฅธ ๋ถ€๋ถ„์ด ๊ฐ™์€ ์‹œ๊ฐ„์— ๋ฉ”๋ชจ๋ฆฌ์˜ ๊ฐ™์€ ์œ„์น˜์— ์ ‘๊ทผํ•  ๋•Œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • Swift ์—์„œ๋Š” ์ž์ฒด ์ˆ˜์ • ์ค‘์— ๊ฐ’์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.

์˜ˆ์‹œ) ์•„๋ž˜์—์„œ ์ค‘๊ฐ„ ์ƒํƒœ๋Š”, ์ƒˆ๋กœ ๋ฐ˜์˜๋œ ๋ฌผํ’ˆ์˜ ๊ฐ€๊ฒฉ์ด total ์— ์ ์šฉ๋˜์ง€ ์•Š์€ ์ƒํƒœ์ด๋‹ค. ์—ฌ๊ธฐ์„œ total ์— ์ ‘๊ทผํ•˜๊ฒŒ ๋˜๋ฉด ์ž˜๋ชป๋œ ๊ฐ’์ด ๋‚˜์˜จ๋‹ค.

NOTE : ๋™์‹œ / ๋‹ค์ค‘ ์“ฐ๋ ˆ๋“œ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•œ ๊ฒฝ์šฐ ๋ฉ”๋ชจ๋ฆฌ ์ถฉ๋Œ์ด ๋นˆ๋ฒˆํ•˜๊ฒŒ ๋ฐœ์ƒํ•œ๋‹ค. ํ•˜์ง€๋งŒ ์˜ˆ์‹œ๋Š” ๋‹จ์ผ ์“ฐ๋ ˆ๋“œ์—์„œ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ์ด๋‹ค.

๋‹จ์ผ ์“ฐ๋ ˆ๋“œ ๋‚ด ์ถฉ๋Œ์€ ์ปดํŒŒ์ผ / ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ๋ฅผ ์ผ์œผํ‚ค๊ฒŒ ๋˜๊ณ ,
๋‹ค์ค‘ ์“ฐ๋ ˆ๋“œ ์ฝ”๋“œ๋Š” Thread Sanitizer ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์“ฐ๋ ˆ๋“œ ๊ฐ„ ์ถฉ๋Œ์„ ์ผ์œผํ‚ค๋Š” ์ ‘๊ทผ์„ ๊ฐ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.


๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ์˜ ํŠน์ง•

์•„๋ž˜ 3๊ฐ€์ง€ ์กฐ๊ฑด์„ ๋ชจ๋‘ ๋งŒ์กฑํ•˜๋Š” 2๊ฐœ์˜ ์ ‘๊ทผ์ด ์žˆ๋‹ค๋ฉด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•œ๋‹ค.

  • ์ ์–ด๋„ ํ•˜๋‚˜๋Š” ์“ฐ๊ธฐ ์ ‘๊ทผ (๋ฉ”๋ชจ๋ฆฌ ์œ„์น˜๋ฅผ ๋ณ€๊ฒฝ) ์ด๊ฑฐ๋‚˜ non-atomic (C atomic ์—ฐ์‚ฐ์ด ์•„๋‹Œ ๊ฒƒ) ์ ‘๊ทผ์ด๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ์˜ ๊ฐ™์€ ์œ„์น˜์— ์ ‘๊ทผํ•œ๋‹ค.
  • ์ ‘๊ทผ ์‹œ๊ฐ„์ด ๊ฒน์นœ๋‹ค. (์ˆœ๊ฐ„์  / ์žฅ๊ธฐ์ )
    • ์ ‘๊ทผ์ด ์‹œ์ž‘๋˜๊ณ , ์ข…๋ฃŒ๋˜๊ธฐ ์ „์— ๋‹ค๋ฅธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” ์ ‘๊ทผ์€ ๋™์‹œ์— ์ด๋ฃจ์–ด์ง„๋‹ค.
    • ๋ฉ”๋ชจ๋ฆฌ์— 2๊ฐœ์˜ ์ฆ‰์‹œ ์ ‘๊ทผ์€ ์ผ์–ด๋‚  ์ˆ˜๊ฐ€ ์—†๋‹ค.
    • ๋ฉ”๋ชจ๋ฆฌ์—๋Š” ์ฆ‰๊ฐ์ ์ธ ์ ‘๊ทผ์ด ์ผ์–ด๋‚จ.

๊ทธ๋Ÿฐ๋ฐ... ๋‹ค๋ฅธ ์ฝ”๋“œ์˜ ์‹คํ–‰์— ๊ฑธ์นœ ๊ฒฝ์šฐ, ๋ฉ”๋ชจ๋ฆฌ์— ์žฅ๊ธฐ ์ ‘๊ทผ์„ ํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด...

  • ์žฅ๊ธฐ ์ ‘๊ทผ์ด ์‹œ์ž‘๋˜๊ณ  ์ข…๋ฃŒ๋˜๊ธฐ ์ „์— ๋‹ค๋ฅธ ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๋‹ค. -> ์˜ค๋ฒ„๋žฉ
  • ์žฅ๊ธฐ ์ ‘๊ทผ์€ ์žฅ๊ธฐ / ์ฆ‰๊ฐ ์ ‘๊ทผ๊ณผ ์˜ค๋ฒ„๋žฉ ๋  ์ˆ˜ ์žˆ๋‹ค.
    • inout ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜
    • ๊ตฌ์กฐ์ฒด๋ฅผ ๋ณ€๊ฒฝํ•˜๋Š” mutating ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ฝ”๋“œ์—์„œ ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ๋‹ค.

2. In-Out ํŒŒ๋ผ๋ฏธํ„ฐ์— ์ถฉ๋Œ ์ ‘๊ทผ

  • ํ•จ์ˆ˜๋Š” ๋ชจ๋“  in-out ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋Œ€ํ•ด ์žฅ๊ธฐ ์“ฐ๊ธฐ ์ ‘๊ทผ ์„ ํ•˜๊ฒŒ ๋œ๋‹ค.
  • non-in-out ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ํ‰๊ฐ€๋œ ํ›„์— in-out ํŒŒ๋ผ๋ฏธํ„ฐ์— ์“ฐ๊ธฐ ์ ‘๊ทผ์„ ์‹œ์ž‘ํ•˜๊ณ , ํ•จ์ˆ˜๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๋™์•ˆ ์“ฐ๊ธฐ ์ ‘๊ทผ์ด ์ง€์†๋œ๋‹ค.
  • inout ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ๋ฉด inout ํŒŒ๋ผ๋ฏธํ„ฐ๊ฐ€ ๋‚˜ํƒ€๋‚˜๋Š” ์ˆœ์„œ๋Œ€๋กœ ๋ฉ”๋ชจ๋ฆฌ ์“ฐ๊ธฐ ์ ‘๊ทผ์„ ์‹œํ–‰ํ•œ๋‹ค.

๋ฌธ์ œ1 : ์ „๋‹ฌ๋œ ์›๋ž˜ ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค.

var stepSize = 1

func increment(_ number: inout Int) {
    number += stepSize // stepSize ๋ฅผ ์ „๋‹ฌํ–ˆ๋Š”๋ฐ ์•ˆ์—์„œ stepSize ์— ์ ‘๊ทผ -> ์˜ค๋ฒ„๋žฉ ์ถฉ๋Œ.
}

increment(&stepSize)
// Error: conflicting accesses to stepSize

ํ•ด๊ฒฐ1 : setpSize ์˜ ๋ณต์‚ฌ๋ณธ์„ ์ง€์ •ํ•ด์„œ inout ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋ณด๋‚ธ๋‹ค.

// Make an explicit copy.
var copyOfStepSize = stepSize
increment(&copyOfStepSize) // ๋ณต์‚ฌ๋ณธ์„ ํ•จ์ˆ˜์˜ ์ธ์ž๋กœ ๋ณด๋ƒ„.

// Update the original.
stepSize = copyOfStepSize
// stepSize is now 2
// ์ฝ๊ธฐ ์ ‘๊ทผ์ด ์“ฐ๊ธฐ ์ ‘๊ทผ์ด ์‹œ์ž‘๋˜๊ธฐ ์ „์— ๋๋‚จ

๋ฌธ์ œ2 : inout ํŒŒ๋ผ๋ฏธํ„ฐ์— ๋‹จ์ผ ๋ณ€์ˆ˜๋ฅผ ๋„˜๊ธฐ๋ฉด ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•œ๋‹ค.

  • ์—ฐ์‚ฐ์ž ์—ญ์‹œ ํ•จ์ˆ˜์ด๋ฏ€๋กœ, inout ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ๋„˜๊ธฐ๋Š” ์—ฐ์‚ฐ์ž๋ผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ์ ‘๊ทผ ์ถฉ๋Œ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
func balance(_ x: inout Int, _ y: inout Int) {
    let sum = x + y
    x = sum / 2
    y = sum - x
}
var playerOneScore = 42
var playerTwoScore = 30
balance(&playerOneScore, &playerTwoScore)  // OK : ๋‘ ์“ฐ๊ธฐ ์ ‘๊ทผ์ด ์˜ค๋ฒ„๋žฉ ๋˜์ง€๋งŒ ๋‹ค๋ฅธ ์ฃผ์†Œ์— ์ ‘๊ทผํ•˜๋Š” ๊ฒƒ์ด๋ฏ€๋กœ ์ƒ๊ด€ ์—†์Œ.
balance(&playerOneScore, &playerOneScore) // Error: ์˜ค๋ฒ„๋žฉ ๋˜๋ฉฐ ๊ฐ™์€ ์ฃผ์†Œ์— ์ ‘๊ทผํ•จ -> conflict

3. ๋ฉ”์„œ๋“œ์—์„œ self ์— ์ถฉ๋Œ ์ ‘๊ทผ

  • ๊ตฌ์กฐ์ฒด์˜ mutating method ๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ํ˜ธ์ถœ๋˜๊ณ  ๋ฐ˜ํ™˜๋ ๋•Œ ๊นŒ์ง€ self ์— ๋Œ€ํ•œ ์“ฐ๊ธฐ ์ ‘๊ทผ์„ ๊ฐ€์ง„๋‹ค.
struct Player {
    var name: String
    var health: Int
    var energy: Int

    static let maxHealth = 10
    mutating func restoreHealth() {
        health = Player.maxHealth
    }
}

// sharedHealth ๋ผ๋Š” ํ•จ์ˆ˜๋ฅผ ๋งŒ๋“ค๋ฉด, self (Player) ์— ๋Œ€ํ•œ ์ค‘๋ณต ์ ‘๊ทผ ๊ฐ€๋Šฅ์„ฑ์ด ์ƒ๊ธด๋‹ค.
extension Player {
    mutating func shareHealth(with teammate: inout Player) {
        balance(&teammate.health, &health)
    }
}

var oscar = Player(name: "Oscar", health: 10, energy: 10)
var maria = Player(name: "Maria", health: 5, energy: 10)
oscar.shareHealth(with: &maria)  // OK : ์˜ค๋ฒ„๋žฉ์€ ๋˜๋‚˜ ๋‹ค๋ฅธ ์ฃผ์†Œ์— ์ ‘๊ทผํ•˜๊ณ  ์žˆ์Œ.

ํ•˜์ง€๋งŒ ๋ณธ์ธ๊ณผ ์ฒด๋ ฅ์„ ๊ณต์œ ํ•œ๋‹ค๋ฉด..? ์ถฉ๋Œ.

oscar.shareHealth(with: &oscar)
// Error: conflicting accesses to oscar


4. ํ”„๋กœํผํ‹ฐ์—์„œ ์ถฉ๋Œ ์ ‘๊ทผ

  • ๊ฐ’ ํƒ€์ž…์˜ ๊ฒฝ์šฐ ๊ฐœ๋ณ„ ๊ตฌ์„ฑ๊ฐ’์œผ๋กœ ๊ตฌ์„ฑ๋˜๊ณ ,
  • ์ผ๋ถ€๋ถ„์„ ๋ณ€๊ฒฝํ•˜๋ฉด ์ƒˆ๋กœ์šด ์ฃผ์†Œ์— ๋ณ€๊ฒฝ๋œ ๊ตฌ์กฐ์ฒด๋ฅผ ํ• ๋‹นํ•˜๊ณ  ๊ฑฐ๊ธฐ๋ฅผ ์ฐธ์กฐํ•ด์„œ ์ „์ฒด ๊ฐ’์ด ๋ณ€๊ฒฝ๋œ๋‹ค.
  • ํ”„๋กœํผํ‹ฐ ์ค‘ ํ•˜๋‚˜์— ์ฝ๊ธฐ / ์“ฐ๊ธฐ ์ ‘๊ทผ์„ ์š”๊ตฌํ•˜๊ฑฐ๋‚˜, ์ „์ฒด ๊ฐ’์— ์ฝ๊ธฐ / ์“ฐ๊ธฐ ์ ‘๊ทผ์„ ์š”๊ตฌํ•˜๊ฒŒ ๋œ๋‹ค.
  • ํŠœํ”Œ์˜ ์š”์†Œ์— ์“ฐ๊ธฐ ์ ‘๊ทผ์ด ๊ฒน์น˜๋ฉด ์ถฉ๋Œ์ด ์ผ์–ด๋‚˜๊ฒŒ ๋œ๋‹ค.
var playerInformation = (health: 10, energy: 20)
balance(&playerInformation.health, &playerInformation.energy)
// Error: conflicting access to properties of playerInformation ๊ฐ™์€ ํŠœํ”Œ ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ์“ฐ๊ธฐ ์ ‘๊ทผ์„ ์š”๊ตฌํ•˜๋ฉด์„œ ์˜ค๋ฒ„๋žฉ ๋˜์–ด ์ถฉ๋Œ

var holly = Player(name: "Holly", health: 10, energy: 10)
balance(&holly.health, &holly.energy)  // Error : ๊ฐ™์€ ๊ตฌ์กฐ์ฒด ์ธ์Šคํ„ด์Šค์— ๋Œ€ํ•œ ์“ฐ๊ธฐ ์ ‘๊ทผ ์˜ค๋ฒ„๋žฉ -> ์ถฉ๋Œ 
// ๋‹ค๋ฅธ ๋ณ€์ˆ˜๊ฐ€ holly ์— ์ ‘๊ทผํ•ด์„œ ๋ญ”๊ฐ€๋ฅผ ๋ฐ”๊พธ๋Š” ๋„์ค‘์— balance ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ถฉ๋Œ.

ํ•ด๊ฒฐ : holly ๊ฐ€ ์ „์—ญ ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹ˆ๋ผ ์ง€์—ญ๋ณ€์ˆ˜๋ผ๋ฉด ์ค‘๋ณต ์ ‘๊ทผ์ด ์•ˆ์ „ํ•  ์ˆ˜ ์žˆ์Œ. 2๊ฐœ์˜ ์ €์žฅ๋œ ํ”„๋กœํผํ‹ฐ๊ฐ€ ์–ด๋–ค์‹์œผ๋กœ๋„ ์ƒํ˜ธ์ž‘์šฉํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๊ทผ๋ฐ... ์™œ?

func someFunction() {
    var oscar = Player(name: "Oscar", health: 10, energy: 10)
    balance(&oscar.health, &oscar.energy)  // OK : health ์™€ energy ๊ฐ€ ์ƒํ˜ธ์ž‘์šฉํ•˜์ง€ ์•Š์„ ๊ฑฐ๋ผ๊ณ  ๋ณด์žฅ์ด ๋จ by ์ปดํŒŒ์ผ๋Ÿฌ - 
    // balance ๊ฐ€ ํ•œ๋ฒˆ๋งŒ ์‹คํ–‰๋˜๊ณ  ์žˆ๊ณ , ์ง€์—ญ ๋ณ€์ˆ˜๋ผ์„œ ํ•จ์ˆ˜ ๋‚ด๋ถ€์—์„œ๋งŒ ์“ฐ์ด๊ณ  ์—†์–ด์ง€๊ธฐ ๋•Œ๋ฌธ. 
    // ๋‹ค๋ฅธ ๊ฒƒ์ด oscar ๋ณ€์ˆ˜์— ์ ‘๊ทผํ•  ์šฐ๋ ค๊ฐ€ ์—†๋‹ค.
}

  • ๊ตฌ์กฐ์ฒด์˜ ํ”„๋กœํผํ‹ฐ์— ์ค‘๋ณต ์ ‘๊ทผ์— ๋Œ€ํ•œ ์ œํ•œ์€ ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ •์„ฑ์„ ์œ„ํ•ด์„œ ํ•ญ์ƒ ํ•„์š”ํ•œ ์˜์—ญ์€ ์•„๋‹ˆ๋‹ค.
  • ๋ฉ”๋ชจ๋ฆฌ์— ๋Œ€ํ•œ ๋ฐฐํƒ€์  ์ ‘๊ทผ ์ด ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ •์„ฑ๋ณด๋‹ค ์ค‘์š”ํ•˜๋‹ค.
  • Swift ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ๋ฐฐํƒ€์ ์ด์ง€ ์•Š์€ ์ ‘๊ทผ์ด ์•ˆ์ „ํ•˜๋‹ค๊ณ  ์ฆ๋ช…๋˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ ์•ˆ์ „ ์ฝ”๋“œ๋ฅผ ํ—ˆ์šฉํ•˜๊ฒŒ ๋œ๋‹ค.
    • ๊ณ„์‚ฐ๋œ ํ”„๋กœํผํ‹ฐ, ํด๋ž˜์Šค ํ”„๋กœํผํ‹ฐ๊ฐ€ ์•„๋‹Œ ์ธ์Šคํ„ด์Šค์˜ ์ €์žฅ๋œ ํ”„๋กœํผํ‹ฐ๋งŒ ์ ‘๊ทผ
    • ๊ตฌ์กฐ์ฒด๋Š” ์ „์—ญ ๋ณ€์ˆ˜๊ฐ€ ์•„๋‹Œ ์ง€์—ญ ๋ณ€์ˆ˜์˜ ๊ฐ’์ž„
    • ๊ตฌ์กฐ์ฒด๋Š” ํด๋กœ์ €์— ์˜ํ•ด ์บก์ณ๋˜์ง€ ์•Š๊ฑฐ๋‚˜ non-escaping ํด๋กœ์ €์— ์˜ํ•ด์„œ๋งŒ ์บก์ฒ˜๋œ๋‹ค.



์ฐธ๊ณ 

https://bbiguduk.gitbook.io/swift/language-guide-1/memory-safety#in-out-conflicting-access-to-in-out-parameters

profile
0๋…„์ฐจ iOS ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€