머리말


100문 100답 List

100문 100답 List 11~20
100문 100답 List 21~30
100문 100답 List 31~40
100문 100답 List 41~50
100문 100답 List 51~60
100문 100답 List 61~70
100문 100답 List 71~80
100문 100답 List 81~90
100문 100답 List 完

시작.

1. Swift의 특징은 무엇인가요?


안전성 및 성능

  • Swift는 안전성과 성능에 중점을 둔 언어로, 코드의 안전성을 높이고 메모리 관리를 향상시켜
    안정적이고 효율적인 프로그램을 작성할 수 있습니다.

현대적이고 간결한 문법

  • 간결하고 읽기 쉬운 문법을 갖추어 개발자가 코드를 빠르게 이해하고 작성할 수 있도록 도와줍니다.

함수형 프로그래밍 지원

  • 함수형 프로그래밍 패러다임을 지원하여 코드의 간결성과 모듈성을 촉진하며,
    함수를 일급 객체로 취급합니다.

객체지향 프로그래밍 지원

  • 객체지향 프로그래밍 개념을 완벽하게 지원하며, 클래스, 상속, 다형성 등을 통해 유연하고 재사용 가능한 코드를 작성할 수 있습니다.

풍부한 표준 라이브러리

  • SwiftiOS, macOS 및 다른 Apple 플랫폼에 대한 풍부한 표준 라이브러리를 내장하고 있어 개발자들이 효과적으로 앱을 개발할 수 있도록 도와줍니다.

멀티패러다임 언이

  • Swift는 객체지향 프로그래밍과 함수형 프로그래밍을 결합한 멀티패러다임 언어로,
    다양한 스타일의 프로그래밍을 지원합니다.

Playgrounds

  • 개발자가 코드를 작성하고 즉시 결과를 확인할 수 있는 Playgrounds기능을 제공하여
    실험적인 코딩 및 학습을 용이하게 합니다.

오픈 소스 및 커뮤니티 참여

  • Swift는 오픈소스로 개발되어 있어 다양한 플랫폼에서 사용이 가능하며,
    개발자 커뮤니티의 활발한 참여가 있습니다.

이 코드는 Player라는 요소를 가진 컬렉션에서 가장 높은 플레이어를 찾아 반환하는 기능을 추가하는 것입니다.
이 기능은 컬렉션이 비어있을 때는 nil을 반환합니다.

// Apple Swfit 공식 홈페이지에서 가져온 예문입니다.
struct Player {
    var name: String
    var highScore: Int
}

extension Collection where Element == Player {
    // 모든 플레이어 중에서 가장 높은 점수를 반환합니다.
    // 컬렉션이 비어있으면 `nil`을 반환합니다.
    func highestScoringPlayer() -> Player? {
        return self.max(by: { $0.highScore < $1.highScore })
    }
}

var players: [Player]? = [Player(name: "최", highScore: 1557)]

var recordHolder: String

if let bestPlayer = players?.highestScoringPlayer() {
    recordHolder = """
        최고 기록을 달성한 플레이어는 \(bestPlayer.name)이며,\
        그의 최고 점수는 \(bestPlayer.highScore)점입니다.
        """
} else {
    recordHolder = "아직 게임이 진행되지 않았습니다."
}

print(recordHolder)
// 최고 기록을 달성한 플레이어는 최이며, 그의 최고 점수는 1557점입니다.

let highestScore = players?.highestScoringPlayer()?.highScore ?? 0
print(highestScore)
// highestScore == 1557

이 스크립트는 players라는 컬렉션에서 가장 높은 점수를 가진 플레이어를 찾아 그 이름과 점수를
출력하거나, 게임이 아직 진행되지 않았다면 해당 메시지를 출력합니다.
또한 가장 높은 점수를 highestScore라는 변수에 할당합니다.

요약

Swift는 Apple의 안전하고 성능이 뛰어난 프로그래밍 언어로, 간결한 문법, 함수형 객체지향 프로그래미 지원, 풍부한 표준라이브러리를 특징으로 갖추고 있습니다. 멀티패러다임 언어로 다양한 프로그래밍 스타일을 지원하며, 오픈 소스로 개발되어 커뮤니티 참여가 활발하게 이루어지고 있습니다. Swift는 iOS, macOS 등 Apple 플랫폼에서 주로 사용되며, Playgrounds 기능을 통해 빠른 실험과 학습이 가능합니다.

2. Optional은 무엇이고 왜 사용되나요?


Optional은 값이 있을수도 없을 수도 있는 상황을 나타내기 위한 Swift의 특별한 데이터 타입 입니다.
이는 프로그램에서 “nil”을 나타내는데 사용되며, 값이 존재하지 않을 때 안전하게 처리할 수 있도록 도와줍니다.
주로 함수에서 값을 반환할 때나 프로퍼티가 초기화 되지 않았을 때 등에 사용됩니다.

let a: Int? = 42
let b: Int? = nil

print("a : \(a)") // Optional(42)
print("b : \(b)") // nil
  • Optional타입은 값을 할당하지 않았을 때 nil값을 갖습니다.
  • Optional타입은 사용 시 Unwrap 과정이 필요합니다.
  • nil이 아닐때만 Unwrap 할 수 있고 nil일때 Unwrap하면 컴파일 에러가 발생합니다.

3. Strong Reference와 Weak Reference의 차이점


Strong Reference (강한 참조)

  • 기본적인 참조 방식이며, 객체를 참조하는 동안 참조 횟수를 증가시킵니다.
  • 다른 객체가 해당 객체를 참조하고 있을 경우, 해당 객체는 메모리에서 해제 되지 않습니다.
  • 주로 클래스 인스턴스 간의 참조에서 사용되며, 기본적으로 Swift에서의 참조는 강한 참조 입니다.
class MyClass {
    var otherObject: OtherClass?

    deinit {
        print("MyClass 인스턴스가 메모리에서 해제됨")
    }
}

class OtherClass {
    var reference: MyClass?

    deinit {
        print("OtherClass 인스턴스가 메모리에서 해제됨")
    }
}

var obj1: MyClass? = MyClass()
var obj2: OtherClass? = OtherClass()

obj1?.otherObject = obj2
obj2?.reference = obj1

obj1 = nil
obj2 = nil
// MyClass는 메모리에서 해제되지 않지만, OtherClass는 메모리에서 해제됨

Weak Reference (약한 참조)

  • 참조하는 동안 참조 횟수를 증가시키지 않으며, 참조하는 객체가 메모라에서 해제되면 자동으로 nil로 설정됩니다.
  • 순환 참조를 방지하기 위해 사용되며, 순환 참조가 발생하지 않도록 돕습니다.
class MyClass {
    var otherObject: OtherClass?
}

class OtherClass {
    weak var reference: MyClass?

    deinit {
        print("OtherClass 인스턴스가 메모리에서 해제됨")
    }
}

var obj1: MyClass? = MyClass()
var obj2: OtherClass? = OtherClass()

obj1?.otherObject = obj2
obj2?.reference = obj1

obj1 = nil
// OtherClass는 메모리에서 해제됨

요약

Strong Reference (강한 참조) : 참조하는 동안 참조 횟수르 증가시키며, 참조하는 객체가 해제되지 않습니다. 주로 클래스 간의 기본 참조 방식으로 사용됩니다.

Weak Reference (약한 참조) : 참조하는 동안 참조 횟수를 증가시키지 않으며, 참조하는 객체가 해제되면 자동으로 nil로 설정됩니다. 순환 참조를 방지하고 메모리 누수를 막기위해 사용됩니다.

특성 강한 참조 (Strong Reference) 약한 참조 (Weak Reference)
참조 횟수 증가 참조하는 동안 참조 횟수가 증가함 참조하는 동안 참조 횟수 증가 없음
nil로 설정 참조 대상이 해제되면 자동으로 nil로 설정 안 됨 참조 대상이 해제되면 자동으로 nil로 설정됨
순환 참조 방지 순환 참조 가능 (메모리 누수 발생 가능) 순환 참조 방지에 유용하게 사용됨
사용처 메모리 해제와 상관없이 계속 참조해야 하는 경우 순환 참조를 방지하거나 메모리 해제와 관련된 경우

4. Delegate 패턴이 무엇이고 어떻게 사용되나요?


Delegate패턴은 객체 간의 통신을 위해 사용되는 디자인 패턴 주 하나로, 주로 Delegate(델리게이트)라 불리는 객체를 통해 다른 객체에게 특정 동작을 위임(delegate)하는 방식을 의미합니다.
이 패턴은 객체 간의 결합도를 낮추고 유연성을 향상시키는 데에 기여합니다.

Delegate 패턴의 주요 구성 요소

  • Delegate(델리게이트): 프로토콜을 채택하여 특정 동작을 수행할 수 있는 메서드나 속성을 선언한 프로토콜을 나타내며, 이 프로토콜을 준수하는 객체를 Delegate로 지정합니다.
  • Delegator(델리게이터): Delegate 프로토콜을 구현하고, Delegate 객체를 참조하는 객체입니다.
    주로 이 객체에서 발생하는 특정 이벤트나 동작을 Delegate에게 위임합니다.

Delegate 패턴의 사용 방법

  • 1.프토토콜 정의: Delegate가 수행할 동작에 대한 프토토콜을 정의합니다.
    protocol MyDelegate {
      func didSomething()
    }
    
  • 2.Delegate 객체 선언: Delegate 프로토콜을 채택한 객체를 선언합니다.
    class MyDelegator {
      var delegate: MyDelegate?
    
      func performAction() {
          // 어떤 작업 수행 후 Delegate에게 특정 동작 위임
          delegate?.didSomething()
      }
    }
    
  • 3.Delegate 객체의 위임: Delegate 객체에서 Delegate에게 위임하고자 하는 동작을 호출합니다.
    class SomeDelegate: MyDelegate {
      func didSomething() {
          print("무언가를 수행했습니다.")
      }
    }
    
    let delegator = MyDelegator()
    let delegateInstance = SomeDelegate()
    delegator.delegate = delegateInstance
    
    delegator.performAction() // "무언가를 수행했습니다." 출력
    

    Delegate 패턴은 주로 UIKit에서 사용되며,
    예를 들어 UITableViewDelegate, UITableViewDataSource등의 프로토콜을 통해 뷰 컨트롤러가
    테이블 뷰의 동작을 커스터마이징하는 데 활용됩니다.
    이를 통해 객체 간의 결합도를 낮추고 유연하고 재사용 가능한 코드를 작성할 수 있습니다.

요약

Delegate 패턴은 객체 간 통신을 위한 디자인 패턴으로, Delegate 객체를 통해 특정 동작을 다른 객체에게 위임하는 방식입니다.
이는 객체 간의 결합도를 낮추고 유연성을 높이는 데에 사용됩니다.
주로 프로토콜을 정의하여 Delegate가 수행할 동작을 명시하고, Delegate 객체에서 해당 동작을 호출하여 다른 객체에게 위임합니다.
UIKit에서는 UITableViewDelegate, UITableViewDataSource 등이 Delegate 패턴을 활용한 대표적인 예시입니다.

5. Swift의 Enum과 Struct의 차이점은 무엇인가요?


Enum (열거형)

  • 종류: Enum은 관련된 값들의 그룹을 정의하며, 각 값은 서로 다른 상태를 나타낼 수 있습니다.
    예를 들어, 계절(Enum)이 있을 수 있고, 각 케이스는 봄, 여름, 가을, 겨울 등을 나타낼 수 있습니다.
  • 메서드: Enum은 메서드를 가질 수 있습니다.
    이 메서드들은 특정 Enum케이스와 관련된 동작을 수행할 수 있습니다.
  • 상속: Enum은 상속이 불가능 합니다.
    enum Season {
      case spring, summer, autumn, winter

      func getDescription() -> String {
          switch self {
          case .spring:
              return "Flowers bloom."
          case .summer:
              return "Warm and sunny."
          case .autumn:
              return "Falling leaves."
          case .winter:
              return "Cold and snowy."
          }
      }
  }

Struct(구조체)

  • 종류: Struct는 데이터의 구조를 표현하며, 값을 저장하고 전달하는 데 사용됩니다.
    클래스와 마찬가지로 프로퍼티와 메서드를 가질 수 있습니다.
  • 메모리 위치: Struct는 값 타입으로, 메모리에 할당된 각 인스턴스가 독립적인 공간을 가지고 있습니다.
    한 인스턴스를 수정해도 다른 인스턴스에 영향을 미치지 않습니다.
  • 상속: Struct는 클래스와 달리 기본적으로 상속이 불가능하지만, Protocol을 사용하여 프로토콜 지향 프로그래밍을 할 수 있습니다.
    struct Point {
      var x: Int
      var y: Int

      mutating func moveByX(_ deltaX: Int, y deltaY: Int) {
          x += deltaX
          y += deltaY
      }
  }

결론

Enum은 주로 연관된 값을 그룹화 하고, 각 케이스마다 다른 동작이 필요한 경우에 사용됩니다.

Struct는 주로 데이터를 그룹화 하고 해당 데이터에 대한 동작을 수행하는 경우에 사용됩니다.

두 타입 모두 값 타입으로 복사되기 때문에, 함수의 인자로 전달하거나 할당할 때 값이 복사됩니다.

특성 Enum Struct
종류(Kind) 연관된 값들의 그룹 데이터 구조를 표현
메서드(Methods) 메서드 가능 메서드 가능
상속(Inheritance) 불가능 기본적으로 불가능, 프로토콜 가능
메모리 위치 한 인스턴스 수정이 다른 영향 없음 값 타입, 인스턴스 독립적인 메모리 영역

6. Swift에서 Protocol이란 무엇인가요?


프로토콜은(Protocol)은 Swift에서 추상석인 청사진으로, 메서드, 프로퍼티 등의 요구사항을 정의합니다.
클래스, 구조체, 열거형 등에서 프로토콜을 채택하여 요구사항을 구현할 수 있으며, 다중 프로토콜 채택도 가능합니다.
프로토콜은 코드 일관성과 다형성을 증가시키는 데에 사용됩니다.

protocol MyProtocol {
    var property: Int { get set }
    func performAction()
}

class MyClass: MyProtocol {
    var property: Int = 0

    func performAction() {
        print("Action performed!")
    }
}
let myObject = MyClass()
print(myObject.property) // 출력: 0
myObject.performAction() // 출력: "Action performed!"

위 예시에서 MyProtocolpropertyperformAction()이라는 요구사항을 갖고 있습니다.
MyClass는 이 프로토콜을 채택하여 요구사항을 구현하고 있습니다.

7. Extension이란 무엇이며 어떻게 사용하나요?


Extension(확장)은 기존의 클래스, 구조체, 열거형 등에 새로운 기능을 추가하거나 기존 기능을 확장하는데 사용되는 기능입니다.
기본 타입에 새로운 프로퍼티, 메서드, 초기화자 등을 추가하거나 프로토콜을 채택할 수 있습니다.
Extension은 기존 타입의 수정 없이 새로운 기능을 추가할 수 있어 유용합니다.

Extension의 기본 구문

extension ExistingType {
    // 새로운 기능 추가
}

예제

// 기존의 Int 타입에 메서드 추가
extension Int {
    func squared() -> Int {
        return self * self
    }
}

let number = 5
let squaredNumber = number.squared() // 25

위의 예제에서는 Int타입에 squared()메서드를 추가했습니다.

확장으로 프로토콜 구현

protocol MyProtocol {
    func myMethod()
}

struct MyStruct: MyProtocol {
    func myMethod() {
        print("My Method")
    }
}

extension Int: MyProtocol {
    func myMethod() {
        print("Extension Method")
    }
}

let instance1 = MyStruct()
instance1.myMethod() // 출력: "My Method"

let instance2: Int = 42
instance2.myMethod() // 출력: "Extension Method"

위의 예제에서는 MyStructMyProtocol을 구현하고, Int타입에도 MyProtocol을 Extension을 통해 구현하였습니다.
결과적으로 두 타입에서 myMethod()를 호출할 수 있습니다.

결론

Extension은 기존 타입에 새로운 기능을 추가하거나 확장하는 데 사용되는 강력한 도구입니다.
이를 통해 기존 코드를 수정하지 않고도 새로운 프로퍼티, 메서드, 초기화자 등을 추가하여 코드를 모듈화하고 확장할 수 있습니다.
Extension은 유연성을 제공하며 프로토콜 구현, 계산된 프로퍼티, 서브스크립트 등 다양한 기능을 추가할 수 있습니다.

8. Swift의 Guard statement에 대해 설명하세요.


gurad문은 Swift에서 제공하는 제어문 중 하나로, 특정 조건이 충족되지 않으면 조기에 함수나 코드 블록을 종료할 수 있습니다.
주로 조건 감사 후 코드의 가독성을 높이고, 조건이나 충족되지 않으면 조기에 에러를 처리하거나 리턴하는 용도로 사용됩니다.

기본 구문

guard condition else {
    // 조건이 충족되지 않을 때 실행되는 코드
    // 예를 들어, 에러 처리 등
    return
}

// 조건이 충족될 때 실행되는 코드

예제

func processUserInput(input: String?){
  guard let unwrappedInput = input, !unwrappedInput.isEmpty else{
    // 입력이 nil이거나 비어있을 경우 처리
    print("Invaild input.")
    return
  }

  // 입력이 유효한 경우 처리
  print("Processing: \(unwrappedInput)")
}

processUserInput(input: nil) // 출력: Invaild input
processUserInput(input: "Hello") // 출력: Processing: Hello

위의 예제에서 guard문은 옵셔널의 언래핑과 비어있는지 여부를 확인하여 유효성을 검사하고,
조건이 충족되지 않으면 조기에 함수를 종료하고 에러를 처리합니다.
이를 통해 코드의 가독성이 향상되고, 조건 충족 여부에 따라 각각의 상황을 처리할 수 있습니다.

결론

guard문은 Swift에서 조건이 충족되지 않으면 조기에 함수나 코드 블록을 종료하는데 사용되는 구문입니다.
주로 옵셔널 값의 언래핑 및 조건 검사 후 코드의 가독성을 높이고, 조건이 충족되지 않을 때 초기에 에러 처리나 종료를 수행합니다.
이를 통해 코드의 안전성과 가독성을 개선하며, 예외적인 상황을 빠르게 처리할 수 있습니다.

9. Swift에서 Type Alias가 무엇인가요?


Swift에서 Type Alias(타입 별칭)은 기존의 데이터 타입에 대해 다른 이름을 부여하는 기능입니다.
즉, 기존 타입에 대한 새로운 이름을 정의하여 코드의 가독성을 향상하거나 코드의 유지보수성을 개선할 수 있습니다.

기본 구문

typealias NewtypeName = ExistingType

예제

typealias Coordinate = (x: Douvle, y: Double)
let point: Coordinate = (2.0, 3.5)
print("X: \(point.x), Y: \(point.y)")

위의 예제에서 Coordinate는 (x: Double, y: Double) 라는 튜플의 새로운 이름입니다.
이를 통해 코드에서 좌표를 표현할 때 더 간결하고 읽기 쉬운 형태로 사용할 수 있습니다.

결론

Type Alias(타입 별칭)은 기존의 데이터 타입에 새로운 이름을 부여하는 기능으로,
코드의 가독성을 높이고 유지보수성을 향상시키는데 사용됩니다.
이를 통해 긴 타입 이름이나 복잡한 구조체, 튜플 등을 간결하게 표현할 수 있으며,
코드의 가독성을 높이고 중복을 줄일 수 있습니다.

10. Swift에서의 Generics에 대해 설명하세요.

Swift에서 Generics(제네릭)은 함수, 메서드, 클래스, 구조체, 열거형 등에서 다양한 데이터 타입을 유연하게 다룰 수 있는 기능을 제공합니다.
Generics를 사용하면 코드의 재사용성을 높이고, 타입 안전성을 유지하면서도 일반적인 알고리즘 및 데이터 구조를 구현할 수 있습니다.

함수에서의 Generics

func swapValue<T>(_ a: inout T, b: inout T){
  let temp = a
  a = b
  b = temp
}

var a = 5
var b = 10
swapValues(&a, &b)
print("a: \(a), b: \(b)") // 출력 "a: 10, b: 5"

위의 예제에서 swapValues함수는 제네릭을 사용하여 어떤 타입의 값이든 교환할 수 있습니다.

클래스에서의 Generics

class Stack<Element> {
  var items = [Elemet()]

  func push(_ item: Element){
    items.append(item)
  }

  func pop() -> Element? {
    return items.popLast
  }
}

let stringStack = Stack<String>()
stringStack.push("Swift")
stringStack.push("Generics")
print(stringStack.pop() ?? "") // 출력: "Generics"

위의 예제에서도 Stack클래스는 제네릭으로 구현되어 어떤 타입의 요소도 저장할 수 있습니다.

결론

Swift에서의 Generics(제네릭)은 여러 타입에서 동작하는 유연하고 안전한 코드를 작성할 수 있게 해주는 강력한 기능입니다.
제네릭을 사용하면 코드의 재사용성이 높아지며, 타입 안전성을 유지하면서도 일반적인 알고리즘 및 데이터 구조를 구현할 수 있습니다.
이는 Swift 언어의 간결하고 안정적인 코드를 작성하는데 큰 도움을 주며, 다양한 타입에서 일반적인 코드를 쉽게 작성할 수 있도록 해줍니다.
Generics를 적절히 사용하면 코드의 가독성과 유지보수성을 높일 수 있습니다.









다음에 계속


100문 100답 List에서 1~10번까지의 질문에 대한 답변입니다.
틀린 답변이 있거나 더 좋은 답변이 있다면 댓글 남겨주시면 적극 반영하겠습니다.
다들 화이팅 입니다.

100문 100답 List 11~20
100문 100답 List 21~30
100문 100답 List 31~40
100문 100답 List 41~50
100문 100답 List 51~60
100문 100답 List 61~70
100문 100답 List 71~80
100문 100답 List 81~90
100문 100답 List 完

이상.