๐—ถ๐—ข๐—ฆ/๐Ÿ iOS ๊ฐœ๋…ํŽธ

[iOS / Swift] ์ ‘๊ทผ ์ œ์–ด์ž(Access Control Levels)

z_ero 2025. 10. 16. 13:58

์ ‘๊ทผ ์ œ์–ด์ž๋ž€?

์ ‘๊ทผ ์ œ์–ด(Access Control)๋Š” ์ฝ”๋“œ๊ฐ€ ์„œ๋กœ ์ƒํ˜ธ์ž‘์šฉํ•  ๋•Œ ๋ชจ๋“ˆ(module) ๊ฐ„, ์†Œ์Šค ํŒŒ์ผ(source file) ๊ฐ„์˜ ์ ‘๊ทผ์„ ์ œํ•œํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์ž…๋‹ˆ๋‹ค.

Swift์˜ ์ ‘๊ทผ ์ œ์–ด๋Š” ๋ชจ๋“ˆ๊ณผ ์†Œ์Šค ํŒŒ์ผ์„ ๊ธฐ์ค€์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์„œ ์†Œ์Šค ํŒŒ์ผ์ด๋ž€ ํ•˜๋‚˜์˜ Swift ์†Œ์Šค ์ฝ”๋“œ ํŒŒ์ผ(.swift)์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

 

๐ŸŽ ๋ชจ๋“ˆ(module)์ด๋ž€?

๋ชจ๋“ˆ(module)์€ ํ•˜๋‚˜์˜ ์ฝ”๋“œ ๋ฐฐํฌ ๋‹จ์œ„๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋ ˆ์ž„์›Œํฌ, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ, ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ชจ๋‘ ๋ชจ๋“ˆ ๋‹จ์œ„๊ฐ€ ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค๋ฅธ ๋ชจ๋“ˆ์˜ ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” import ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ,

๋ฐ˜๋Œ€๋กœ import๋กœ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์€ ๋ชจ๋‘ ๋ชจ๋“ˆ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ: UIKit, Foundation, SwiftUI ๋“ฑ

 

Swift์—์„œ๋Š” ์ด ๋‹ค์„ฏ ๊ฐ€์ง€ ์ ‘๊ทผ ์ œ์–ด์ž๋ฅผ ์ œ๊ณตํ•˜๋Š”๋ฐ์š”! ์ฐจ๊ทผ์ฐจ๊ทผ ํ•˜๋‚˜์”ฉ ์•Œ์•„๋ด…์‹œ๋‹ค~

1. open

  • ์™ธ๋ถ€ ๋ชจ๋“ˆ์—์„œ๋„ ์ ‘๊ทผ๊ณผ ์žฌ์ •์˜(override) ๊ฐ€๋Šฅ
  • ์ฃผ๋กœ ํ”„๋ ˆ์ž„์›Œํฌ๋‚˜ SDK์—์„œ ์‚ฌ์šฉ
open class Developer {
    open func introduce() {
        print("์ €๋Š” iOS ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค!")
    }
}

2. public

  • ์™ธ๋ถ€ ๋ชจ๋“ˆ์—์„œ ์ ‘๊ทผ์€ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ ์ƒ์†·์žฌ์ •์˜ ๋ถˆ๊ฐ€๋Šฅ
public class Notice {
    public func announce() {
        print("๋“€๋“€๋“€ ๊ฐ€๋‚˜๋””")
    }
}

3. internal (๊ธฐ๋ณธ๊ฐ’)

  • ๊ฐ™์€ ๋ชจ๋“ˆ ๋‚ด๋ถ€์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ (๊ธฐ๋ณธ๊ฐ’)
  • ๋ณ„๋„๋กœ ์ ‘๊ทผ ์ œ์–ด์ž๋ฅผ ์•ˆ ์“ฐ๋ฉด ์ž๋™์œผ๋กœ internal์ด ์ ์šฉ๋จ
class Study {
    func start() {
        print("์• ๋‹ˆ๋ฉ”์ด์…˜ ์Šคํ„ฐ๋”” ์‹œ์ž‘ ๐ŸŽ")
    }
}

4. fileprivate

  • ๊ฐ™์€ ํŒŒ์ผ ์•ˆ์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
fileprivate class Helper {
    func setup() {
        print("์˜ค๋Š˜๋„ ์Šค์œ„ํ”„ํŠธ ๊ณต๋ถ€ ์ค‘...")
    }
}

class StudyRoom {
    let helper = Helper()
    func run() {
        helper.setup()  // ๊ฐ™์€ ํŒŒ์ผ์ด๋‹ˆ๊นŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
    }
}

5. private

  • ๊ฐ™์€ ์„ ์–ธ ๋‚ด๋ถ€(ํด๋ž˜์Šค ๋‚ด๋ถ€)์—์„œ๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
class Diary {
    private var content = "ํ™”์ดํŒ…!"

    func showDiary() {
        print(content)
    }
}

let diary = Diary()
diary.showDiary()  // ์ ‘๊ทผ ๊ฐ€๋Šฅ
// diary.content < ์™ธ๋ถ€์—์„œ ์ ‘๊ทผ ๋ถˆ๊ฐ€

 


์ ‘๊ทผ ์ œ์–ด์ž๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

์ ‘๊ทผ ์ œ์–ด์ž๋Š” ์ฝ”๋“œ์˜ ๊ตฌ์กฐ์  ์•ˆ์ •์„ฑ๊ณผ ๋ณด์•ˆ์„ฑ์„ ๋†’์ด๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ด๋Š” ๊ฐ์ฒด ์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์˜ ํ•ต์‹ฌ ๊ฐœ๋…์ธ ์บก์Аํ™”(encapsulation)์™€ ๋ฐ€์ ‘ํ•œ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋ถˆํ•„์š”ํ•œ ์™ธ๋ถ€ ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•จ์œผ๋กœ์จ, ์ฝ”๋“œ์˜ ์œ ์ง€๋ณด์ˆ˜์„ฑ๊ณผ ์‹ ๋ขฐ์„ฑ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š”๊ฑฐ์ฃ .

1. ์บก์Аํ™”

์ ‘๊ทผ ์ œ์–ด์ž๋Š” ํด๋ž˜์Šค๋‚˜ ๊ตฌ์กฐ์ฒด์˜ ๋‚ด๋ถ€ ๋™์ž‘์„ ์™ธ๋ถ€์—์„œ ์ง์ ‘ ๋ณผ ์ˆ˜ ์—†๊ฒŒ ์ˆจ๊ธฐ๋Š” ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ์™ธ๋ถ€์— ๊ณต๊ฐœํ•˜๊ณ , ๋‚˜๋จธ์ง€๋Š” ๊ฐ์ถ”์–ด ์ฝ”๋“œ๋ฅผ ๋” ์•ˆ์ „ํ•˜๊ณ  ๊น”๋”ํ•˜๊ฒŒ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋‚ด๋ถ€๋ฅผ ์ž์œ ๋กญ๊ฒŒ ๋ฐ”๊พธ๋ฉด์„œ๋„ ์™ธ๋ถ€์— ์˜ํ–ฅ์„ ์ฃผ์ง€ ์•Š๋Š” ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

์˜ˆ๋ฅผ ๋“ค์–ด, ์ ‘๊ทผ ์ œ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ฝ”๋“œ์™€ ์‚ฌ์šฉํ•œ ์ฝ”๋“œ๋ฅผ ๋น„๊ตํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ ‘๊ทผ ์ œ์–ด๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ

class User {
    var password: String = "1234"
}

let user = User()
user.password = "0000"   // ์™ธ๋ถ€์—์„œ ์ง์ ‘ ์ˆ˜์ • ๊ฐ€๋Šฅ
print(user.password)     // "0000"

์ด ๊ฒฝ์šฐ ์™ธ๋ถ€ ์ฝ”๋“œ์—์„œ password ํ”„๋กœํผํ‹ฐ๋ฅผ ์ง์ ‘ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๊ฐ€ ์™ธ๋ถ€์—์„œ ์‰ฝ๊ฒŒ ๋ณ€๊ฒฝ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ์ „ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ ‘๊ทผ ์ œ์–ด๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒฝ์šฐ

class User {
    private var password: String = "1234"

    func checkPassword(_ input: String) -> Bool {
        return input == password
    }
}

let user = User()
// user.password = "0000"   // ์˜ค๋ฅ˜: 'password'๋Š” private ๋ฉค๋ฒ„๋ผ ์™ธ๋ถ€ ์ ‘๊ทผ ๋ถˆ๊ฐ€

print(user.checkPassword("1234"))   // true
print(user.checkPassword("0000"))   // false

์—ฌ๊ธฐ์„œ๋Š” password ํ”„๋กœํผํ‹ฐ๋ฅผ private์œผ๋กœ ์„ ์–ธํ•ด ์™ธ๋ถ€ ์ฝ”๋“œ์—์„œ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์ˆจ๊ฒผ์Šต๋‹ˆ๋‹ค.

๋Œ€์‹  checkPassword()๋ผ๋Š” ๊ณต๊ฐœ๋œ(public) ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด์„œ๋งŒ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ฒ˜๋Ÿผ ์ ‘๊ทผ ์ œ์–ด๋ฅผ ํ™œ์šฉํ•˜๋ฉด ๋‚ด๋ถ€ ๋™์ž‘์€ ๋ณดํ˜ธํ•˜๋ฉด์„œ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ์™ธ๋ถ€์— ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

2. ์ฝ”๋“œ ์•ˆ์ •์„ฑ

์ ‘๊ทผ ์ œ์–ด๋Š” ์˜๋„์น˜ ์•Š์€ ์ ‘๊ทผ์ด๋‚˜ ์ˆ˜์ •์œผ๋กœ๋ถ€ํ„ฐ ์ฝ”๋“œ๋ฅผ ๋ณดํ˜ธํ•ฉ๋‹ˆ๋‹ค.

ํŠนํžˆ ํŒ€ ๋‹จ์œ„ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ, ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๊ฐ€ ๋‚ด๋ถ€ ๊ตฌํ˜„์— ์ง์ ‘ ์ ‘๊ทผํ•˜๊ฑฐ๋‚˜ ์ž˜๋ชป๋œ ๊ฐ’์„ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.

3. API ์„ค๊ณ„

๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋‚˜ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์„ค๊ณ„ํ•  ๋•Œ ์ ‘๊ทผ ์ œ์–ด๋Š” ํ•„์ˆ˜์ ์ž…๋‹ˆ๋‹ค.

์™ธ๋ถ€ ๊ฐœ๋ฐœ์ž์—๊ฒŒ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋งŒ ๋ช…์‹œ์ ์œผ๋กœ ๊ณต๊ฐœ(public ๋˜๋Š” open) ํ•˜๊ณ ,

๋‚ด๋ถ€ ๊ตฌํ˜„ ์„ธ๋ถ€ ์‚ฌํ•ญ์€ private ๋˜๋Š” internal๋กœ ์ˆจ๊น€์œผ๋กœ์จ ๋ช…ํ™•ํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด API ์‚ฌ์šฉ์ž๋Š” ์˜๋„๋œ ๋ฐฉ์‹์œผ๋กœ๋งŒ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ ,

๋‚ด๋ถ€ ์ฝ”๋“œ๋ฅผ ์ž˜๋ชป ๊ฑด๋“œ๋ ค ์‹œ์Šคํ…œ์ด ๋ถˆ์•ˆ์ •ํ•ด์ง€๋Š” ์ผ์„ ์˜ˆ๋ฐฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

4. ๋ณด์•ˆ

์ ‘๊ทผ ์ œ์–ด๋Š” ๋ณด์•ˆ์ ์ธ ์ธก๋ฉด์—์„œ๋„ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด, ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋‚˜ ๊ฐœ์ธ ๋ฐ์ดํ„ฐ์™€ ๊ฐ™์€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋Š”

private์ด๋‚˜ fileprivate๋กœ ์„ ์–ธํ•˜์—ฌ ์™ธ๋ถ€์—์„œ ์ง์ ‘ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•˜๋„๋ก ์ฐจ๋‹จํ•ฉ๋‹ˆ๋‹ค.

5. ์„ฑ๋Šฅ ์ตœ์ ํ™”

์ ‘๊ทผ ๋ฒ”์œ„๊ฐ€ ์ข์„์ˆ˜๋ก ์ปดํŒŒ์ผ๋Ÿฌ๋Š” ์ฝ”๋“œ์˜ ์‹คํ–‰ ํ๋ฆ„์„ ๋” ์ •ํ™•ํ•˜๊ฒŒ ์˜ˆ์ธกํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

private์ด๋‚˜ final๋กœ ์„ ์–ธ๋œ ๋ฉค๋ฒ„๋Š” ์ •์  ๋””์ŠคํŒจ์น˜(static dispatch) ๋ฐฉ์‹์œผ๋กœ ํ˜ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์—,

๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ์‹œ์ ์— ๋Ÿฐํƒ€์ž„ ํƒ์ƒ‰ ๊ณผ์ •์„ ๊ฑฐ์น˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ ๊ฒฐ๊ณผ ํ•จ์ˆ˜ ํ˜ธ์ถœ ์†๋„๊ฐ€ ๋นจ๋ผ์ง€๊ณ  ์ „์ฒด ์‹คํ–‰ ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์ ‘๊ทผ ์ œ์–ด๋ฅผ ์ ์ ˆํžˆ ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ๋‹จ์ˆœํ•œ ๋ณด์•ˆ๋ฟ ์•„๋‹ˆ๋ผ ์ตœ์ ํ™” ์ธก๋ฉด์—์„œ๋„ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•