๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
  • Dev Blog
iOS/Swift

[Swift] Extension

by ์œ ์ง„์˜ 2024. 5. 20.

์Šค์œ„ํ”„ํŠธ์—์„œ Extension์€ ์–ด๋–ป๊ฒŒ ์‚ฌ์šฉ๋˜๋‚˜์š”? 

Swift์—์„œ Extension์€ Class, Struct, Enum, Protocol ํƒ€์ž…์— ๋ฉ”์„œ๋“œ๋‚˜ ํ”„๋กœํผํ‹ฐ๋ฅผ ์ถ”๊ฐ€์ ์œผ๋กœ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. Extension ๊ทœ์น™์€ ์ €์žฅ ํ”„๋กœํผํ‹ฐ๋Š” ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๊ณ , ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ๋งŒ ์ถ”๊ฐ€ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ๋˜ํ•œ, ์†Œ๋ฉธ์ž๋Š” ์ถ”๊ฐ€ํ•  ์ˆ˜ ์—†๊ณ , ์ƒ์„ฑ์ž๋Š” convenience init ๋งŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

๐Ÿ“Œ ๊ธฐ๋Šฅ ํ™•์žฅ ๊ด€์ ์—์„œ์˜ Extension

์šฐ๋ฆฌ๊ฐ€ ํ”ํžˆ ๊ธฐ๋Šฅ์˜ ํ™•์žฅ์„ ํ•  ๋•Œ์—๋Š” ์ƒ์†์„ ์‚ฌ์šฉํ•ด์„œ ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๋Ÿฌํ•œ ์ˆ˜์ง์  ํ™•์žฅ์€ ๊ฒฐํ•ฉ๋„๊ฐ€ ๋†’์•„์ ธ ์ƒ์œ„ ํด๋ž˜์Šค์˜ ๊ตฌํ˜„์ด๋‚˜ ๋ณ€๊ฒฝ์ด ํ•˜์œ„ ํด๋ž˜์Šค์— ์˜ํ–ฅ์„ ๋ผ์น˜๋ฏ€๋กœ ์บก์Šํ™”๋ฅผ ํ•ด์น  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

 

์•„๋ž˜ ์ฝ”๋“œ๋Š” ์ƒ์†์œผ๋กœ ๊ธฐ๋Šฅ ํ™•์žฅ์„ ํ–ˆ์„ ์‹œ ์บก์Šํ™”๋ฅผ ํ•ด์น˜๋Š” ์ฝ”๋“œ ์˜ˆ์‹œ์ž…๋‹ˆ๋‹ค.

class S {
  var array = [Int]()
  func add(_ element: Int) { array.append(element) }
  func addAll(_ elements: [Int]) {
    elements.forEach { self.add($0) }
  }
}

class SS: S {
  var count = 0

  override func add(_ e: Int) {
    count += 1
    super.add(e)
  } 

  override func addAll(_ es: [Int]) {
    count += es.count
    super.addAll(es)
  }
}

let ss = SS()

ss.addAll([1, 2, 3])
print(ss.count) // ?

 

์œ„ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๋ฉด 3 ์•„๋‹Œ 6์ด ์ถœ๋ ฅ๋ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ์˜๋„์น˜ ์•Š๊ฒŒ ์™ธ๋ถ€(๋ถ€๋ชจ ํด๋ž˜์Šค)์—์„œ ์ž์‹ ์˜ ์ƒํƒœ(count ํ”„๋กœํผํ‹ฐ)๊ฐ€ ๋ณ€๊ฒฝ๋˜๋ฏ€๋กœ ์บก์Šํ™”๊ฐ€ ์ œ๋Œ€๋กœ ์ด๋ฃจ์–ด์ง€์ง€ ๋ชปํ–ˆ๋‹ค๊ณ  ๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Swift๋Š” ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋Š” ์ƒ์†์— ์˜ํ•œ ์ˆ˜์ง์  ํ™•์žฅ ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜ํ‰์  ํ™•์žฅ์„ ํ•  ์ˆ˜ ์žˆ๋Š” Extension์„ ์ œ๊ณตํ•ด ์ค๋‹ˆ๋‹ค.

 

 

์Šค์œ„ํ”„ํŠธ์—์„œ ์ถ”์ƒ ํด๋ž˜์Šค๋ฅผ ๋งŒ๋“ค๋ ค๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผ ํ• ๊นŒ์š”?

Swift๋Š” ์ถ”์ƒ ํด๋ž˜์Šค ๋ฌธ๋ฒ•์„ ์ง€์›ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ, ์ถ”์ƒ ํด๋ž˜์Šค์™€ ๋™์ผํ•œ ๋™์ž‘์„ ํ•˜๋„๋ก ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ์กด์žฌํ•ฉ๋‹ˆ๋‹ค.

 

๐Ÿ“Œ ํ”„๋กœํ† ์ฝœ๊ณผ extension์„ ํ™œ์šฉ

protocol Vehicle {
    func start()
    func beep()
    func stop()
}

extension Vehicle {
    func start() {
        print("Starting the vehicle.")
    }

    func stop() {
        print("Stopping the vehicle.")
    }
}

class Car: Vehicle {
    func beep() {
	    print("beep~~~!")
	}
}

var car = Car()
car.beep() // beep~~~!
car.stop() // Stopping the vehicle.

 

 

๐Ÿ“Œ ์ƒ์†๊ณผ fatalError๋ฅผ ํ™œ์šฉ

class BaseClass {
    func someMethod1() {
    	print("someMethod1 called.")	
    }
    
    func someMethod2() {
        fatalError("This method must be overridden")
    }
}

class SubClass: BaseClass {
    override func someMethod2() {
        print("Implemented in SubClass")
    }
}

var sub = SubClass()
sub.someMethod1() // someMethod1 called.
sub.someMethod2() // Implemented in SubClass

 

 

๐Ÿšจ ์ถ”์ƒ ํด๋ž˜์Šค๋ž€?
์ถ”์ƒ ํด๋ž˜์Šค๋ž€ ์ถ”์ƒ ๋ฉ”์„œ๋“œ, ์ฆ‰ ์„ ์–ธ๋ถ€๋งŒ ์กด์žฌํ•˜๊ณ  ๊ตฌํ˜„ ์ฝ”๋“œ๊ฐ€ ์—†๋Š” ๋ฉ”์„œ๋“œ๊ฐ€ ํ•˜๋‚˜๋ผ๋„ ์žˆ๋Š” ํด๋ž˜์Šค๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค. ์ถ”์ƒ ํด๋ž˜์Šค์˜ ํŠน์ˆ˜ ํ˜•ํƒœ์ธ ์ธํ„ฐํŽ˜์ด์Šค๋„ ์กด์žฌํ•˜๋Š”๋ฐ, ์ธํ„ฐํŽ˜์ด์Šค๋Š” ๋ชจ๋“  ๋ฉ”์„œ๋“œ๊ฐ€ ๋‹ค ์ถ”์ƒ ๋ฉ”์„œ๋“œ์ธ ํ˜•ํƒœ๋ฅผ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

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

Swift์—์„œ๋Š” Protocol์„ ํ†ตํ•ด ์ถ”์ƒ ํด๋ž˜์Šค์™€ ์ธํ„ฐํŽ˜์ด์Šค ๊ฐœ๋…์„ ๋ชจ๋‘ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ๋ณธ์ ์œผ๋กœ ์ธํ„ฐํŽ˜์ด์Šค์ฒ˜๋Ÿผ ํ”„๋กœํผํ‹ฐ๋‚˜ ๋ฉ”์„œ๋“œ๋ฅผ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ณ , ์ถ”์ƒ ํด๋ž˜์Šค์ฒ˜๋Ÿผ extension์„ ํ†ตํ•ด ๊ธฐ๋ณธ ๊ตฌํ˜„์„ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

 

Extension์€ ๋ฉ”์„œ๋“œ๋ฅผ Override ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

Swift์˜ Extension์€ ์ƒˆ๋กœ์šด ๋ฉ”์„œ๋“œ, ์—ฐ์‚ฐ ํ”„๋กœํผํ‹ฐ, ์ƒ์„ฑ์ž(convenience init)๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆœ ์žˆ์ง€๋งŒ ๋ฉ”์„œ๋“œ๋ฅผ override ํ•  ์ˆ˜๋Š” ์—†์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, @objc dynamic ํ‚ค์›Œ๋“œ๊ฐ€ ๋ถ™์€ ๋ฉ”์„œ๋“œ์˜ ๊ฒฝ์šฐ Table Dispatch๊ฐ€ ์•„๋‹Œ Objective-C์˜ Message Dispatch ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝ๋˜๊ธฐ ๋•Œ๋ฌธ์— extension์—์„œ๋„ ์˜ค๋ฒ„๋ผ์ด๋”ฉ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ, ๊ธฐ๋ณธ์ ์œผ๋กœ Swift ๊ณต์‹๋ฌธ์„œ์—์„œ๋Š” Extension์„ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•œ ๊ฒƒ์ž„์„ ์–ธ๊ธ‰ํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ extension์„ ํ†ตํ•œ ์˜ค๋ฒ„๋ผ์ด๋”ฉ์€ ์ง€์–‘ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

 

class A {
    @objc dynamic func something() {
      print("something")
    }
}

class AA: A {}

extension AA {
    override func something() {
        print("SOMETHING")
    }
}

let a = AA()
a.something() // SOMETHING

๋Œ“๊ธ€