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

[iOS / Swift] final ํ‚ค์›Œ๋“œ์™€ ์„ฑ๋Šฅ์  ์ด์ ์— ๋Œ€ํ•ด์„œ

z_ero 2025. 10. 16. 11:12

final ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ด์œ 

final ํ‚ค์›Œ๋“œ๋ฅผ ์•Œ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ƒ์† ๊ฐœ๋…์„ ๋จผ์ € ์งš๊ณ  ๋„˜์–ด๊ฐ€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

๐ŸŽ ์ƒ์†(Inheritance)

์ƒ์†์€ ๊ฐ์ฒด์ง€ํ–ฅ ํ”„๋กœ๊ทธ๋ž˜๋ฐ(OOP)์˜ ํ•ต์‹ฌ ๊ฐœ๋… ์ค‘ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค.

Swift์—์„œ๋Š” ํด๋ž˜์Šค(class)๋งŒ ์ƒ์†์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ๊ตฌ์กฐ์ฒด(struct)๋‚˜ ์—ด๊ฑฐํ˜•(enum)์€ ์ƒ์†์„ ์ง€์›ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

 

์ฆ‰, ๊ธฐ์กด ํด๋ž˜์Šค์˜ ์†์„ฑ๊ณผ ๊ธฐ๋Šฅ์„ ๋ฌผ๋ ค๋ฐ›์•„ ์ƒˆ๋กœ์šด ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด ๋ฐ”๋กœ ์ƒ์†์ž…๋‹ˆ๋‹ค!

class Developer {
    func introduce() {
        print("์ €๋Š” iOS ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.")
    }
}

class Zero: Developer {
    func coding() {
        print("๋ง‰๊ฑธ๋ฆฌ์กฐ ํ™”์ดํŒ…!")
    }
}

let ze = Zero()
ze.introduce()   // ์ถœ๋ ฅ: ์ €๋Š” iOS ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.
ze.coding()      // ์ถœ๋ ฅ: ๊ณต๋ถ€ ํ™”์ดํŒ…!

 

์œ„ ์˜ˆ์‹œ์—์„œ Zero ํด๋ž˜์Šค๋Š” Developer๋ฅผ ์ƒ์†๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

๋•๋ถ„์— Developer์˜ introduce() ๋ฉ”์„œ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฑฐ์ฃ !

 

๋ฉ”์„œ๋“œ ์žฌ์ •์˜(Override)

์ƒ์†๋ฐ›์€ ๊ธฐ๋Šฅ์„ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์ž์‹ ์—๊ฒŒ ๋งž๊ฒŒ ๋™์ž‘์‹œํ‚ค๊ณ  ์‹ถ์„ ๋•Œ๋Š”
override ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜(override) ํ•ฉ๋‹ˆ๋‹ค.

class iOSTeamMember: Developer {
    override func introduce() {
        print("์ €๋Š” ์•„์š” ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.")
    }
}

let member = iOSTeamMember()
member.introduce()  // ์ถœ๋ ฅ: ์ €๋Š” ์•„์š” ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค.

 

์ด์ฒ˜๋Ÿผ ๋ถ€๋ชจ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋ฅผ ๊ทธ๋Œ€๋กœ ์“ฐ์ง€ ์•Š๊ณ ,

ํ”„๋กœ์ ํŠธ๋‚˜ ์—ญํ• ์— ๋งž๊ฒŒ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด override์˜ ํ•ต์‹ฌ์ž…๋‹ˆ๋‹ค.

 

๐ŸŽ final ํ‚ค์›Œ๋“œ์˜ ์—ญํ• 

๊ทธ๋Ÿผ ์ด์ œ ์˜ค๋Š˜์˜ ์ฃผ์ œ์ธ final ํ‚ค์›Œ๋“œ์˜ ์—ญํ• ์— ๋Œ€ํ•ด ์•Œ์•„๋ด…์‹œ๋‹ค!


final ํ‚ค์›Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด
์ƒ์†๊ณผ ์žฌ์ •์˜๋ฅผ ๋ชจ๋‘ ๋ง‰์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฆ‰, ๋” ์ด์ƒ ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์ƒ๊ธฐ๊ฑฐ๋‚˜ ์˜ค๋ฒ„๋ผ์ด๋“œ๋˜๋Š” ์ผ์„ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// final ํด๋ž˜์Šค ์˜ˆ์‹œ
final class School {
    func welcome() {
        print("์ƒˆ ํ•™๊ธฐ๊ฐ€ ์‹œ์ž‘๋˜์—ˆ์Šต๋‹ˆ๋‹ค!")
    }
}

// โŒ ์˜ค๋ฅ˜: 'School' ํด๋ž˜์Šค๋Š” final์ด๋ผ ์ƒ์† ๋ถˆ๊ฐ€๋Šฅ
// class MySchool: School { }


// final ๋ฉ”์„œ๋“œ ์˜ˆ์‹œ
class Student {
    final func study() {
        print("์—ด์‹ฌํžˆ ๊ณต๋ถ€ ์ค‘์ž…๋‹ˆ๋‹ค ๐Ÿ“š")
    }
}

// โŒ ์˜ค๋ฅ˜: 'study()' ๋ฉ”์„œ๋“œ๋Š” final์ด๋ผ ์žฌ์ •์˜ ๋ถˆ๊ฐ€๋Šฅ
// class HighSchoolStudent: Student {
//     override func study() { print("๊ฒŒ์ž„ํ•˜๋‹ค๊ฐ€ ๊ณต๋ถ€ ์‹œ์ž‘!") }
// }

 

์œ„ ์ฝ”๋“œ์ฒ˜๋Ÿผ final์„ ๋ถ™์ด๋ฉด “๋” ์ด์ƒ ๋ณ€๊ฒฝ๋˜๋ฉด ์•ˆ ๋˜๋Š” ํด๋ž˜์Šค๋‚˜ ๋ฉ”์„œ๋“œ”๋ฅผ ๋ช…ํ™•ํ•˜๊ฒŒ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด๋กœ์จ ์ฝ”๋“œ ๊ตฌ์กฐ๊ฐ€ ์•ˆ์ •๋˜๊ณ , ์˜ˆ์ธก ๋ถˆ๊ฐ€๋Šฅํ•œ ์ˆ˜์ •์œผ๋กœ ์ธํ•œ ์˜ค๋ฅ˜๋ฅผ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐ŸŽ ์–ธ์ œ final์„ ์‚ฌ์šฉํ• ๊นŒ?

ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ํ•„์š” ์—†๋Š” ํด๋ž˜์Šค ๋” ์ด์ƒ ์ƒ์† ๊ตฌ์กฐ๊ฐ€ ํ™•์žฅ๋˜์ง€ ์•Š์•„๋„ ๋˜๋Š” ๊ฒฝ์šฐ
๊ธฐ๋Šฅ์ด ๋ณ€๊ฒฝ๋˜๋ฉด ์•ˆ ๋˜๋Š” ๋ฉ”์„œ๋“œ ์ค‘์š”ํ•œ ๋กœ์ง์„ ๋ณดํ˜ธํ•˜๊ณ  ์‹ถ์„ ๋•Œ
์•„ํ‚คํ…์ฒ˜์ ์œผ๋กœ ๋…๋ฆฝ๋œ ๋ชจ๋“ˆ ์˜ˆ: ํ•ต์‹ฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง, ๊ณตํ†ต ์œ ํ‹ธ ํด๋ž˜์Šค ๋“ฑ
ํŒ€ ๋‚ด ๊ณต์šฉ ๊ธฐ๋ฐ˜ ์ฝ”๋“œ ์—ฌ๋Ÿฌ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ ‘๊ทผํ•˜๋”๋ผ๋„ ๊ตฌ์กฐ๊ฐ€ ๊นจ์ง€์ง€ ์•Š๋„๋ก ๋ฐฉ์ง€


์˜ˆ๋ฅผ ๋“ค์–ด, ์ œ๊ฐ€ ์ž‘์„ฑํ•œ AppManager ํด๋ž˜์Šค๊ฐ€ ์•ฑ ์ „์ฒด์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ๋œ๋‹ค๋ฉด,

ํ•ด๋‹น ํด๋ž˜์Šค๋Š” ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž๋“ค์ด ์ž„์˜๋กœ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ์ƒ์†๋ฐ›์ง€ ๋ชปํ•˜๊ฒŒ final๋กœ ์„ ์–ธํ•˜๋Š” ๊ฒƒ์ด ์ข‹๊ฒ ์ฃ ?


final ํ‚ค์›Œ๋“œ์˜ ์„ฑ๋Šฅ์  ์ด์ 

final์€ ๋‹จ์ˆœํžˆ ์ƒ์† ๊ธˆ์ง€๋ฅผ ์œ„ํ•œ ๋„๊ตฌ๊ฐ€ ์•„๋‹ˆ๋ผ, ์„ฑ๋Šฅ ํ–ฅ์ƒ์—๋„ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ ์ด์œ ๋Š” Swift์˜ Dynamic Dispatch(๋™์  ๋””์ŠคํŒจ์น˜) ๋™์ž‘ ๋ฐฉ์‹๊ณผ ๊ด€๋ จ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐ŸŽ Dynamic Dispatch๋ž€?

Swift์—์„œ ํด๋ž˜์Šค์˜ ๋ฉ”์„œ๋“œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋Ÿฐํƒ€์ž„ ์‹œ์ ์— ํ˜ธ์ถœ ๋Œ€์ƒ์ด ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์–ด๋–ค ํ•˜์œ„ ํด๋ž˜์Šค๊ฐ€ ์‹ค์ œ๋กœ ์ด ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ํ–ˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•˜๋ฏ€๋กœ, ์ปดํŒŒ์ผ ์‹œ์ ์—๋Š” ์ •ํ™•ํ•œ ํ˜ธ์ถœ ๋Œ€์ƒ์„ ๋ชจ๋ฆ…๋‹ˆ๋‹ค.

์ด๋Ÿฐ ๋ฐฉ์‹์„ Dynamic Dispatch๋ผ๊ณ  ํ•ฉ๋‹ˆ๋‹ค.

class Base {
    func sayHello() {
        print("๊ธฐ๋ณธ ์ธ์‚ฌ")
    }
}

class Sub: Base {
    override func sayHello() {
        print("ํ•˜์œ„ ํด๋ž˜์Šค ์ธ์‚ฌ")
    }
}

let base: Base = Sub()
base.sayHello()  // ์‹ค์ œ ์ถœ๋ ฅ: ํ•˜์œ„ ํด๋ž˜์Šค ์ธ์‚ฌ

 

Swift๋Š” sayHello()๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „, ๊ฐ์ฒด๊ฐ€ Base๊ฐ€ ์•„๋‹Œ Sub ํƒ€์ž…์ธ์ง€ ๋Ÿฐํƒ€์ž„์—์„œ ํ™•์ธํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
→ ์ฆ‰, ๊ฐ„์ ‘ ํ˜ธ์ถœ(indirect call) ์ด ์ผ์–ด๋‚ฉ๋‹ˆ๋‹ค.

 

๐ŸŽ final๋กœ ์ธํ•œ ์ตœ์ ํ™”

ํ•˜์ง€๋งŒ ๋งŒ์•ฝ sayHello()๊ฐ€ final์ด๋ผ๋ฉด,

Swift ์ปดํŒŒ์ผ๋Ÿฌ๋Š” “์ด ํ•จ์ˆ˜๋Š” ์žฌ์ •์˜๋  ์ˆ˜ ์—†๋‹ค”๋Š” ์‚ฌ์‹ค์„ ์ด๋ฏธ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

class Base {
    final func sayHello() {
        print("๊ธฐ๋ณธ ์ธ์‚ฌ - ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€")
    }
}

let obj = Base()
obj.sayHello()  // ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ์ง์ ‘ ํ˜ธ์ถœ ๊ฐ€๋Šฅ

 

์ด ๊ฒฝ์šฐ Dynamic Dispatch๊ฐ€ ํ•„์š” ์—†์œผ๋ฏ€๋กœ, ์ปดํŒŒ์ผ๋Ÿฌ๋Š” Static Dispatch(์ •์  ๋””์ŠคํŒจ์น˜) ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

์ฆ‰, ์ปดํŒŒ์ผ ์‹œ์ ์— ํ•จ์ˆ˜ ์ฃผ์†Œ๋ฅผ ๋ฐ”๋กœ ๊ฒฐ์ •ํ•˜๋ฏ€๋กœ ์„ฑ๋Šฅ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

 

๋ฐ˜์‘ํ˜•