iOS InterView Questions

DevelopRecord·2022년 5월 9일
0

이 블로그는 iOS, Swift를 공부하며 모르는 부분이나

헷갈렸던 부분을 정리하는 공간입니다.

그러기에 간혹 정확한 정보가 아닌 틀린 내용이 있을 수 있습니다.

오늘부터 iOS 관련 인터뷰 내용을 작성 및 추가하고, 또 틀린 부분은 계속 수정해 나갈 예정입니다.

수정해야 할 내용, 추가해야 할 내용들은 언제든지 댓글 남겨주시면 감사하겠습니다!

iOS


1 ) Bounds와 Frame의 차이점은 무엇인가요?

우선 Bounds와 Frame은 UIView의 instance property입니다.
둘 다 타입은 CGRect이므로 origin(x, y), width, height값을 가집니다.

Frame은 상위뷰. 즉, View의 좌표값과 크기를 Superview의 좌표시스템 내에서 나타냅니다.
Bounds는 자신만의 뷰. 즉, View의 좌표값과 크기를 자신만의 좌표시스템 내에서 나타냅니다.

2 ) 실제 디바이스가 없을 경우 개발 환경에서 할 수 있는 것과 없는 것은 무엇인가요?

하드웨어
가속도 센서 가압계 센서,주변광 센서를,GPS 센서, 줌인, 줌아웃, 카메라, 마이크, 전화

✔︎ GPS는 위, 경도값을 수동으로 잡아줄 수는 있습니다.

API
푸쉬알림의 수신 및 발신, HandOff

3 ) 앱의 콘텐츠나 데이터 자체를 저장/보관하는 특별한 객체를 무엇이라고 하나요?

UserDefault
key-value 쌍으로 디바이스에 데이터를 저장하는 방식의 인터페이스입니다.
주로 앱의 설정값을 저장하고 불러오기 위한 용도로 사용됩니다.
float, double, Int, String, Bool 형태의 값 뿐만 아니라,
NSData, NSDictionary, NSString, NSNumber, NSArray, NSDate유형의 객체도 저장 가능합니다.

아카이브
객체 아카이브는 객체 그래프를 따라 객체의 데이터 내용을 저장하는 방식입니다.

아카이빙
iOS에서 모델 객체를 저장하는 가장 기본적인 방법중 하나입니다.
객체의 아카이빙이란 그 객체의 프로퍼티를 모두 기록하고 파일 시스템에 그 내용을 저장합니다.

언아카이빙
아카이브한 데이터로부터 객체를 다시 만드는 작업을 말합니다.

4 ) 앱 화면의 콘텐츠를 표시하는 로직과 관리를 담당하는 객체를 무엇이라고 하나요?

UIViewController

  • UIKit앱의 뷰 계층 구조를 관리하는 객체입니다.
  • 뷰의 사용자 상호작용에 응답합니다.
  • 앱의 전체 인터페이스와 레이아웃을 담당합니다.
  • 데이터가 변경되면 뷰의 콘텐츠를 업데이트하여 최신화할 수 있습니다.

5 ) App thinning에 대해서 설명해 주세요.

App Store가 각각의 기기의 환경에 맞게 앱을 최적화하여 설치하는 기술을 말합니다.

예를 들면, 하나의 앱에 다양한 기능이 있는데 내 앱에 필요한 것만 담을 수 있게 만든 기능을 App Slicing이라 일컫고,
이 서로다른 디바이스들을 다양한 앱 번들을 만들고, 전달하는 과정입니다.

6 ) 앱이 시작할 때 main.c 에 있는 UIApplicationMain 함수에 의해서 생성되는 객체는 무엇인가요?

앱이 실행되면 UIApplicationMain 함수를 호출합니다.
이후 UIApplication 객체와 delegate를 생성하고 shared클래스에 접근해 메소드를 호출하여 객체에 접근합니다.

7 ) @Main에 대해서 설명해 주세요.

애플리케이션이 실행될 때 코드의 첫 진입점을 찾게되는데, 이때 @Main을 통해 진입점을 알려줄 수 있습니다.
Swift 5.3부터는 @Main을 사용합니다. (@UIApplicationMain 대신에)

8 ) 앱이 foreground에 있을 때와 background에 있을 때 어떤 제약사항이 있나요?

foreground는 사용자가 앱을 실행중이고 현재 화면일 때를 말합니다.
CPU를 비롯한 시스템 자원할당의 우선순위가 높은 상태입니다.

따라서, 메모리 및 기타 시스템 리소스에 대해서 background 보다 높은 우선순위를 가지며,
필요에 따라 background 상태의 앱을 종료할 수도 있습니다.

background는 사용자가 앱을 이용하다 Home screen으로 들어가서 사용자에게 보이지 않는 상태를 말합니다.
하지만 음악 앱과 같이 다른 앱을 사용하더라도 앱을 종료하면 안되는 상황도 존재합니다.

따라서, background 상태의 앱은 가능한 메모리 및 시스템 리소스를 적게 사용해야 하고,
foreground보다 우선순위가 낮기 때문에 foreground보다 더 낮은 자원을 할당 받습니다.

9 ) 상태 변화에 따라 다른 동작을 처리하기 위한 AppDelegate 메서드들을 설명하시오.

didFinishLaunchingWithOptions
앱이 실행된 직후 사용자의 화면에 보여지기 직전에 호출됩니다.

willFinishLaunchingWithOptions
앱이 최초 실행될 때 호출됩니다.

applicationWillResignActive
앱이 InActive 상태일 때 호출됩니다.
InActive: 앱을 실행 중 전화가 왔을때, 잠금상태, 멀티태스킹 상태일 때
Active: InActive 상태가 아닐 때

applicationDidEnterBackground
앱이 백그라운드 상태로 전환된 직후에 호출됩니다.

applicationWillEnterForeground
앱이 Active 상태가 되기 직전 사용자에게 화면이 보여지기 직전에 호출됩니다.

applicationDidBecomeActive
앱이 Active 상태로 전환된 직후 호출됩니다.

applicationWillTerminate
앱이 종료되기 직전에 호출됩니다.

10 ) 앱이 In-Active 상태가 되는 시나리오를 설명하시오.

InActive: 앱을 실행 중 전화가 왔을때, 잠금상태, 멀티태스킹 상태일 때
Active: InActive 상태가 아닐 때

11 ) scene delegate에 대해 설명하시오.

iOS12까지는 대부분 하나의 앱에 하나의 window였지만,
iOS13부터는 iPad에 멀티 윈도우라는 기능이 추가되면서
하나의 window에서 여러개의 scene을 가질 수 있게 되었습니다.

그래서 원래는 AppDelegate의 역할인 UILifeCycle을 SceneDelegate가 받게 되어 scene이 생성되거나 삭제되는 것을 관리합니다.

** 중요) 그럼 할 일이 없어진 AppDelegate는 무슨 일을 하나요?
1. 앱의 가장 중요한 데이터 구조를 초기화하는 작업을 합니다.
2. 앱의 scene을 환경설정(Configuration)합니다.
3. 앱 밖에서 발생한 알림(배터리 부족, 다운로드 완료) 등에 대한 알림에 대응합니다.
4. 특정한 scene, view, viewController에만 국한되지 않고 앱 자체를 타겟하는 이벤트에 대응합니다.
5. 애플 푸쉬 알림 서비스와 같이 실행시 요구되는 모든 서비스를 등록합니다.

12 ) UIApplication 객체의 컨트롤러 역할은 어디에 구현해야 하나요?

이것에 대한 정답 알고계신분 알려주시면 감사하겠습니다!ㅠㅠ

13 ) App의 Not running, Inactive, Active, Background, Suspended에 대해 설명해 주세요.

  • Not running: 실행되지 않았거나, 시스템에 의해 종료된 상태
  • InActive: 앱을 실행 중 전화가 왔을때, 잠금상태, 멀티태스킹 상태일 때
  • Active: 앱이 실질적으로 활동하고 있는 상태. 즉, InActive 상태가 아닐 때
  • Background: 앱을 실행하다 사용자가 Home screen으로 들어가서 사용자에게 보이지 않는 상태
  • Suspended: 백그라운드 상태에서 활동을 멈춘 상태. 빠른 재실행을 위하여 메모리에 적재된 상태지만, 실질적으로 동작하고 있지는 않음. 메모리가 부족하면 강제종료 함.

14 ) NSOperationQueue 와 GCD Queue 의 차이점을 설명하세요.

NSOperationQueue
NSOperationQueue는 operation을 관리하는 큐 입니다.
준비상태, 상호 운용 종속성, 우선순위 등을 기반으로 실행합니다. 다만 우선순위가 같을 경우에는 큐에 먼저 들어온 순서대로 처리합니다.
큐에 한번 들어가면 작업이 끝났다고 보고가 들어올 때까지 대기열에 남아있습니다.
KVO(Key Value Observing)을 사용하여 작업 현황을 감시가 필요할 때 적합합니다.
GCD에서는 사용할 수 없는 기능들(취소, 재개, 중지)을 제공하지만 구현이 복잡하며 무겁습니다.

GCD Queue
iOS에서 쉽고 편한 멀티 스레딩 처리를 위해 제공되는 API입니다.
작업이 간단하게 처리되거나 특정 유형의 시스템 처리를 비동기적으로 해야할 때 적합합니다.(예를 들면 타이머, 프로세스 등의 처리)
오버헤드가 발생할 수도 있지만 사용하기에 매우 간편합니다.
메인 큐에서 작업 항목을 동기적으로 실행하면 교착 상태(Deadlock)가 발생할 수 있습니다.

15 ) GCD API 동작 방식과 필요성에 대해 설명하세요.

동작방식
해야할 일(코드)을 Operation으로 Wrapping 후, Queue에 넣습니다.
이후 Queue에 남는 스레드에 작업을 배분합니다.
Serial, Concurrent, sync, async

필요성

  • 이미지 다운로드와 같은 오래 걸리는 작업들을 동기적으로 처리하게 되면 처리하는 동안에는 화면이 멈추게 됩니다. 이는 사용자에게 불편함을 초래하게 되므로써 비동기로 백그라운드에서 동시에 작업을 처리해 주는 것이 필요합니다.
  • 기존에는 스레드를 사용하려면 직접 스레드를 생성하고 관리해야 합니다.
    GCD를 사용하면 생성, 유지, 삭제 등을 개발자가 신경쓸 필요 없이 해야할 작업(코드)들을 큐에 예약하기만 하면 돼서 편리합니다.

16 ) Global DispatchQueue 의 Qos 에는 어떤 종류가 있는지, 각각 어떤 의미인지 설명하세요.

Concurrency(동시성)
여러개의 스레드가 존재하며 OS 스케쥴러가 이 스레드들을 관리합니다.
코어가 1개인 싱글코어 하드웨어는 한번에 한개의 스레드만 가동되기에 컨텍스트 스위치를 통해 스레드들을 오가면서 작업을 수행합니다.
반면 멀티코어 하드웨어는 동시에 여러개의 스레드를 처리할 수 있기에 컨텍스트 스위치가 필요 없습니다.

GCD(Grand Central Dispatch)
멀티코어 환경에서 최적화된 프로그래밍을 지원하도록 애플이 만든 기술입니다.

Queue
GCD는 dispatch queue를 관리하며 클래스명은 DispatchQueue입니다.
Serial Queue와 Concurrent Queue가 있습니다.

Qos
Global Queue의 우선순위는 Qos가 결정합니다.
1. userInteractive

  • main thread에서 작업합니다.
  • 인터페이스 새로고침, 애니메이션 수행과 같이 사용자와 직접적으로 상호작용하는 작업입니다.
  • 가장 높은 레벨의 우선순위이기에 즉각적으로 처리되지 않으면 UI가 중단된 것처럼 보일 수 있습니다.
  • 거의 순식간에 끝이 납니다.

2. userInitiated

  • 사용자가 시작한 작업이며 저장된 문서를 열거나 인터페이스에서 무언가를 클릭할 때와 같이 즉각적인 결과가 필요합니다.
  • 사용자와 상호작용을 하는데 필요하기 때문에 반응성과 성능에 중점을 둡니다.
  • 반응시간은 거의 순식간이며 몇 초 또는 그 이하입니다.

3. default

  • 작업을 분류하는데 사용하는 것이 아니며, 이름 그대로 Qos 정보가 할당되지 않은 작업들은 default로 처리되며, GCD global queue는 이 레벨에서 실행됩니다.

4. utility

  • 작업을 완료하는데 약간의 시간이 걸릴 수 있습니다. 다만 즉각적인 결과가 필요하지는 않습니다.
  • 유틸리티 작업은 사용자가 직접 볼 수 있는 progress bar가 있으며, 반응성, 성능 및 에너지 효율성에 균형을 유지하는데 중점을 둡니다.

5. background

  • 백그라운드에서 작동하며 동기화, 백업 등과 같은 사용자가 볼 수 없는 작업입니다.

17 ) iOS 앱을 만들고, User Interface를 구성하는 데 필수적인 프레임워크 이름은 무엇인가요?

코코아터치(Cocoa Touch)
코코아터치 프레임워크란 iOS 개발 환경을 구축하기 위한 최상위 프레임워크입니다.
object-c, swift에 상속하여 사용하는 Foundation, UIKit을 포함한 대부분의 클래스와 객체들이 모두 코코아터치 프레임워크에 속합니다.

UIKit
사용자의 인터페이스를 처리 및 관리하기 위한 프레임워크입니다.
주로 처리되는 사용자 이벤트는 제스처 처리, 애니메이션, 그림그리기, 이미지 처리, 텍스트 처리 등이 있습니다.
테이블뷰, 버튼, 슬라이더 버튼, 텍스트 필드 등과 같은 화면을 구성하는 요소도 포함됩니다.
자주 사용하는 UIViewController, UIView, UITableView처럼 앞에 UI가 붙는 클래스들을 사용하려면 반드시 UIKit을 상속해야 합니다.

Foundation
프로그램의 중심을 담당하는 프레임워크입니다.
기본적인 원시 데이터(String, Int, Double) 등이 Foundation에 포함되어 있기에
기본적인 Foundation을 상속하지 않으면 사용하기에 어려움이 있습니다.
Foundation에 있는 대부분의 처리들은 UIKit을 상속하는 상태라면 Foundation을 상속할 필요가 없습니다.

18 ) Foundation Kit은 무엇이고 포함되어 있는 클래스들은 어떤 것이 있는지 설명하세요.

Number, Data, String: 원시 데이터 타입 사용
Collection: Array, Dictionary, Set과 같은 collection 타입 사용
Date and Time: 날짜와 시간을 계산하거나 비교하는 작업
Data Formatting: 숫자, 날짜, 측정값 등을 문자열로 변환하거나 그 반대 작업
Filter and Sorting: 컬렉션의 요소를 검사하거나 정렬하는 작업

19 ) Delegate란 무언인가 설명하고, retain 되는지 안되는지 그 이유를 함께 설명하세요.

Delegate란 어떤 객체가 수행해야 할 작업을 부분적으로 확장하여 대신 처리하는 것을 의미합니다.
retain cycle은 객체에 대한 메모리가 해제되지 않아 메모리 누수가 발생하는 현상을 의미합니다.(두 클래스가 서로 강한 참조를 하게되면 retain cycle이 발생하게 됩니다.)

이 때 참조를 weak로 선언하면 강한 참조가 되지 않아 객체의 메모리가 해제되면 자동으로 nil이 됩니다.

20 ) NotificationCenter 동작 방식과 활용 방안에 대해 설명하세요.

특정 개체가 NotificationCenter에 등록된 이벤트를 발생시키면
해당 이벤트를 처리할 것이라고 등록된 Observer들이 이 이벤트에 대한 행동을 취하는 것이 NotificationCenter 입니다.

활용방안은 특정 데이터의 변경이나 키보드의 Dismiss 여부 등에 대해 활용할 수 있습니다.

21 ) UIKit 클래스들을 다룰 때 꼭 처리해야하는 애플리케이션 쓰레드 이름은 무엇인가요?

메인 스레드

22 ) App Bundle의 구조와 역할에 대해 설명하세요.

App Bundle은 성공적인 작동을 위해 애플리케이션에 필요한 모든 것을 저장합니다.
1. executable code(애플리케이션의 코드를 포함하는 실행파일)
2. image, sound, nib 파일과 같은 리소스
3. info.plist
4. Launch image

23 ) 모든 View Controller 객체의 상위 클래스는 무엇이고 그 역할은 무엇인가요?

모든 View Controller 객체의 상위 클래스는 UIViewController입니다.
UIViewController는 뷰의 내용 업데이트, 사용자와의 상호작용, 뷰의 컨텐츠 업데이트, 뷰 크기 조정, 전체 인터페이스의 레이아웃을 관리합니다.

24 ) 자신만의 Custom View를 만드려면 어떻게 해야 하는지 설명하세요.

UIView를 상속받는 클래스를 생성합니다. UIView는 두개의 필수 생성자가 존재합니다.
override init - 코드로 뷰를 만들 때 사용되는 생성자
required init - 스토리보드를 통해서 View를 연결할 때 사용되는 생성자

25 ) View 객체에 대해 설명하세요.

화면의 직사각형 영역에 대한 컨텐츠를 관리하는 객체입니다. 모든 뷰에 공통적인 동작을 정의하며,
UIButton, UIimageView, UILabel과 같은 모든 뷰 클래스의 상위 클래스입니다.

26 ) UIView에서 Layer 객체는 무엇이고 어떤 역할을 담당하나요?

UIView에 CALayer 타입인 layer를 가지고 있습니다. 이 Layer 객체는 UIView의 작업 중에서 뷰 위에 컨텐츠나 애니메이션을 그리는 역할을 합니다.
UIView의 역할은 크게 세가지로 분류할 수 있습니다.
1. 화면 표시
2. 터치 이벤트
3. subview 관리

27 ) UIWindow 객체의 역할은 무엇인가요?

앱의 시각적 컨텐츠를 담습니다.
뷰들과 다른 애플리케이션 객체들에게 터치 이벤트를 전달하는 중요한 역할을 수행합니다.
오리엔테이션 변화를 쉽게 하기 위해 다른 뷰 컨트롤러들과 협력합니다.

28 ) UINavigationController의 역할이 무엇인가요?

네비게이션 컨트롤러는 컨테이너 뷰 컨트롤러로써 네비게이션 스택을 사용하여 다른 뷰 컨트롤러를 관리하는 역할을 합니다.

29 ) TableView를 동작 방식과 Cell을 출력하기 위해 최소한 구현해야 하는 DataSource 메소드들을 설명하세요.

뷰 컨트롤러는 테이블 뷰의 데이터소스와 델리게이트를 설정하고 reloadData 메시지를 보냅니다.
데이터소스는 UITableView 개체로부터 numberOfRowsInSection: 메시지를 수신하고 테이블보기의 섹션 수를 반환합니다.
각 섹션에 대해 데이터소스는 tableView : numberOfRowsInSection : 메시지를 수신하고 섹션의 행 수를 반환합니다.
데이터소스는 테이블 뷰에 표시되는 각 행에 대해 tableView : cellForRowAt 메시지를 수신합니다.
각 행에 대해 UITableViewCell 개체를 구성하고 반환합니다.

필수 DataSource 메소드

tableView(_:numberOfRowsInSection) -> Int : 섹션별 cell 개수를 리턴합니다.
tableView(_:cellForRowAt:) -> UITableViewCell : 반환할 TableViewCell을 정의합니다.

30 ) 하나의 View Controller 코드에서 여러 TableView Controller 역할을 해야 할 경우 어떻게 구분해서 구현해야 하는지 설명하세요.

  1. 각각의 셀들을 register 함수로 등록합니다.
    2-1. cellForRowAt 메소드에서 tableView 종류로 구분해서 사용
    2-2. tag로 구분해서 사용
    2-3. indexPath별로 구분해서 사용
  2. 각각의 tableView들의 contentSize를 구독하면서 동적으로 관리

31 ) setNeedsLayout와 setNeedsDisplay의 차이에 대해 설명하세요.

setNeedsLayout 메소드는 layoutSubviews 메소드를,
setNeedsDisplay 메소드는 draw 메소드를 시스템이 호출하게끔 유도합니다.
layoutSubviews 메소드는 view의 position이나 layout에 관한 관찰 변화를 적용시키고,
draw 메소드는 다음 드로잉 사이클이 오면 그 때 그려야 할 컨텐츠들을 동시에 적용시킵니다.

32 ) NSCache와 딕셔너리로 캐시를 구성했을때의 차이를 설명하시오.

딕셔너리는 메모리가 부족하면 삭제하는 코드를 작성해야 하지만,
NSCache는 자동으로 메모리가 관리됩니다.
NSCache는 Thread-safe하기 때문에 데이터를 쓸 때마다 lock을 해줄 필요가 없습니다.

33 ) URLSession에 대해서 설명하세요.

앱과 서버간의 데이터를 주고받기 위해서 HTTP 프로토콜을 이용해서 데이터를 주고받는 애플에서 제공하는 API입니다.

34 ) prepareForReuse에 대해서 설명하세요.

테이블 뷰를 사용할 때 보통 셀을 재사용하는 경우가 있습니다.
재사용된 셀에서 보여주지 않아야 하는 텍스트, 버튼 등이 보여지는 경우가 있는데, 때문에 셀을 재사용할 때에는 반드시 모든 값이 초기화 되어야 합니다.
이럴 때 호출되는 함수가 prepareForReuse입니다.

35 ) 다크모드를 지원하는 방법에 대해 설명하세요.

  1. UIColor 내장 System Color 사용
  2. Custom Color 생성하여 사용

36 ) ViewController의 생명주기를 설명하세요.

1. viewDidLoad # 뷰의 컨트롤러가 메모리에 로드되고 난 후에 호출
2. viewWillAppear # 뷰가 나타날 것이라는 것을 컨트롤러에 알림
3. viewDidAppear # 뷰가 나타난 것을 컨트롤러에 알림
4. viewWillDisAppear # 뷰가 사라지기 직전에 컨트롤러에 알림
5. ViewDidDisAppear # 뷰가 사라지면 컨트롤러에 알림

37 ) TableView와 CollectionView의 차이점을 설명하세요.

TableView와 CollectionView 둘다 UIScrollView를 상속받는 서브클래스로 다양한 데이터를 표시할 때 사용합니다.
TableView는 1차원의 형태로, CollectionView는 2차원의 형태로 리스트를 보여준다는 차이점이 있습니다.
TableView는 비교적 간단한 데이터 목록을 표시할 때 사용하면 좋고,
CollectionView는 다양한 모습으로 커스터마이징할 때 사용하면 좋습니다.

Auto layout


1 ) 오토레이아웃을 코드로 작성하는 방법은 무엇인가요? (3가지)

  • 앵커(Anchor)를 통해서 구현합니다.
let button = UIButton()
button.translatesAutoresizingMaskIntoConstraints = false
button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
button.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
  • NSLayoutConstraint 인스턴스로 구현합니다.
var button = NSLayoutConstraint(item: button2, 
					 attribute: .width,
                     relatedBy: .greaterThanOrEqual,
                     toItem: nil,
                     attribute: .notAnAttribute,
                     multiplier: 1.0,
                     constant: 50.0)
  • Visual Format Language를 통해 구현합니다.

Visual Format Language는 매개변수 값을 넘기는 것이 아닌 특정한 형식에 맞춰서 간단하게 Auto layout을 구현할 수 있습니다.

H:[button(>=50)] // 버튼의 너비를 50보다 크거나 같게
V:[button]-10-[label] // 버튼과 레이블 사이의 간격을 10으로

2 ) hugging, resistance에 대해서 설명하세요.

hugging: 예를 들어 두 버튼이 각각 뷰의 SafeArea의 왼쪽, 오른쪽에 붙어있다고 가정하고 두 버튼들을 서로 붙였을 때 가운데의 빈 여백을 누가 채울것인지에 대한 결정을 할 때 사용합니다.

resistance: resistance는 hugging과 반대로, 공간이 부족할 때 누가 줄어들 것인지에 대한 결정을 할 때 사용합니다.

3 ) Intrinsic Size에 대해서 설명하세요.

뷰의 속성만을 고려한 자연스러운 크기입니다.
다시 말해, 버튼의 타이틀이 길어지면 자동으로 버튼 자체의 크기도 같이 자연스럽게 커지는 것을 말합니다.

4 ) 스토리보드를 이용했을때의 장단점을 설명하세요.

장점

  • 빠른 초기화: 뷰를 만드는데 오랜 시간이 걸리지 않습니다.
  • 시각화: 앱을 흐름을 바로바로 한눈에 확인이 가능합니다.
  • 낮은 진입장벽: 코드를 몰라도 초보자들이 예쁜 뷰를 만들 수 있습니다.

단점

  • 생산성: 앱이 커지고 스토리보드 로딩시간이 길어지게 되면 오히려 생산성도 떨어지게 됩니다.
  • 가독성: 스토리보드가 방대해지면 읽기도 어려워지고 난잡해 보여서 가독성이 떨어집니다.
  • 협업성: 스토리보드가 XML 포맷에다가 읽기도 어렵기 때문에 다수의 인원이 수정을 하게 되면 Merge Conflict 처리에 어렵습니다.
  • 재사용성: 스토리보드로 만든 뷰는 재사용하기가 어렵습니다.
  • 번거로움: 스토리보드로 만든 뷰는 코드와 연결하기 위해서는 일일이 Identifier를 부여해줘야 하는데 비교적 번거롭습니다.

5 ) Safearea에 대해서 설명하세요.

컨텐츠가 가리지 않는 영역을 보장하는 것을 의미합니다.
iPhone X 부터 4개의 라운드코너, 노치 디자인으로 인해 safeArea 영역 적용이 필수적으로 추가되었습니다.

6 ) Left Constraint 와 Leading Constraint 의 차이점을 설명하세요.

left/right는 사용자가 보는 왼쪽/오른쪽 위치 속성입니다.
leading/trailingreading direction의 시작과 끝을 나타내는 위치 속성입니다.
우리가 주로 사용하는 한국어나 영어는 기본적으로 왼쪽에서 오른쪽으로 읽지만,
아랍권에서는 오른쪽에서 왼쪽으로 읽습니다.
그래서 디바이스의 시스템 언어 설정에 따라 영향을 받습니다.
뷰의 레이아웃도 마찬가지로 left/right로 지정하면 아랍권에서는 위치가 반전되어 보여지고 경우에 따라 뷰의 레이아웃이 크게 바뀔 수 있습니다.
이런 문제를 해결하기 위하여 leading/trailing을 사용하면 위치를 자동으로 flip해주기에 후자의 방법을 애플에서는 권장하고 있습니다.

Swift


1) struct와 class와 enum의 차이를 설명하세요.

class는 참조 타입이지만 struct와 enum은 값 타입입니다.
class는 상속이 가능하지만 struct와 enum은 상속이 불가능합니다.

structclass
Type스택이라고 부르는 메모리 공간에 값을 저장. 값을 전달할 때마다 복사본 생성. 값 형식힙에 값을 저장. 스택에는 값의 주소를 저장함. 값을 전달하면 복사본은 생성되지 않고, 주소만 전달. 참조 형식
Deinitializer(소멸자)XO
Inheritance(상속)XO

2) class의 성능을 향상시킬수 있는 방법들을 나열해 보세요.

  • 힙 보다는 스택 메모리를 할당하려고 노력합니다.
    class보단 struct나 enum을 사용합니다.
    class는 힙 할당, struct나 enum은 스택 할당.

  • reference counting을 적게 만듭니다.
    class에서 string타입의 변수 사용을 줄입니다. string은 struct타입이지만 문자열 컨텐츠를 힙에 저장하기 때문입니다.

  • dynamic dispatch보다 static dispatch를 지향합니다.
    class를 선언할 때 상속되지 않는 class에 final을 붙이면 성능이 향상됩니다.

3) COW(Copy-On-Write)는 어떤 방식으로 동작하나요?

컴퓨터 프로그래밍에서 복사 동작을 할 때,
실제 원본이나 복사본이 수정되기 전까지는 복사를 하지 않고 원본 리소스를 공유합니다. 원본이나 복사본에서 수정이 발생할 경우에 그 때 복사 작업을 수행합니다.
Swift에서는 CollectionType을 복사할 때 위 동작이 발생합니다.

array1 = [1, 2, 3, 4]
array2: [Int] = arrary1

위 코드 작업을 수행했을 때 array2에 바로 [1, 2, 3, 4]라는 값을 가지고 있지 않습니다. array2는 array1을 참조만 하는 형태가 됩니다.
하지만 여기서 array2나 1에서 값을 수정한다면 이때 비로소 array2에 독립적인 값을 갖게 됩니다.
즉, COW는 불필요한 복사와 메모리 할당을 줄이기 위해 사용합니다.

4) Convenience init은 무엇인가요?

Designated init은 Swift의 초기화 이니셜라이저입니다..
이 init은 클래스의 모든 프로퍼티가 초기화 될 수 있도록 해줘야 합니다.

Class Person {
	var name: String
    var age: Int
    var gender: String
    
    init(name: String, age: Int, gender: String) {
    	self.name = name
        self.age = age
        self.gender = gender
    }
    // 만약 하나의 프로퍼티라도 초기화하지 않는다면 아래의 에러가 발생합니다.
    // Return from initializer without initializing all stored properties.
}

convenience init은 보조 이니셜라이저입니다.
클래스의 원래 이니셜라이저인 init을 도와주는 역할을 합니다.

Class Person {
	var name: String
    var age: Int
    var gender: String
    
    init(name: String, age: Int, gender: String) {
    	self.name = name
        self.age = age
        self.gender = gender
    }
    
    convenience init(age: Int, gender: String) {
    	self.init(name: "DevelopRecord", age: age, gender: gender)
    }
}

따라서 convenience init을 사용하려면 반드시 init(Designated init)이 반드시 먼저 선언되어야 합니다.

5) AnyObject는 무엇인가요?

모든 클래스 타입을 지정할 수 있는 프로토콜입니다.
delegate 변수를 만들 때 순환참조를 방지하기 위해 weak 키워드를 사용할 때가 있는데 이때 주로 사용합니다.

6) Optional이란 무엇인가요?

특정한 변수에 값이 있을수도, 없을수도 있다는 것을 명시적으로 알려줍니다.

var str1: String? = "Hi Swift"
print(str1) // Optional("Hi Swift")

이 경우에 str1에 값이 있을수도, 혹은 없을수도 있기에 Hi Swift가 아닌 Optional("Hi Swift")를 출력합니다.
이럴 땐 안전한 방식의 Optional Binding이나 변수에 기본값을 줍니다.
또는 Forced Unwrapping 방식을 사용할 수도 있습니다.
강제 언래핑 방식은 변수에 값이 없을 때(nil)는 런타임 에러를 반환하기에 가급적 권장하지 않는 방식입니다.

7) struct가 무엇이고 어떻게 사용하나요?

struct는 변수나 프로퍼티를 모아서 하나의 형태로 사용할 수 있는 구조체를 의미합니다.
struct에 변수나 프로퍼티를 정의한 후 외부에서 인스턴스를 생성해 구조체 안에 정의되어 있는 프로퍼티와 메서드에 접근하여 사용할 수 있습니다.

  • COW 방식
  • 값이 스택에 저장되어 RC가 증가하지 않음.

8) Subscripts이 무엇인가요?

class, struct, enum에서 Collection 타입의 특정 멤버 요소에 쉽게 접근하기 위한 방법입니다.
인스턴스 이름 뒤에 대괄호로 감싼 값을 써줌으로써 인스턴스 내부의 특정 값에 접근할 수 있습니다.

  • 읽기 쓰기 가능
subscript(index: Int) -> Int {
	get {
    	// 적절한 반환 값
    }
    set {
    	// 적절한 set 액션
    }
}
  • 읽기 전용
subscript(index: Int) -> Int {
	// 적절한 반환 값
}

9) String은 왜 Subscript로 접근이 안되나요?

String은 struct 타입이고 Character의 컬렉션 타입입니다.
Swift의 Character는 한개 이상의 Unicode Scalar로 이루어져 있어 크기가 가변적입니다.
따라서, str[n]의 방식이 아닌 str.index 방식을 사용해야 합니다.

10) instance 메소드와 class 메소드의 차이점은 무엇인가요?

  • instance 메소드
    특정 클래스, 구조체, 열거형의 인스턴스에 속하는 함수입니다.
    인스턴스 프로퍼티 접근 및 수정을 제공하거나 인스턴스 프로퍼티의 목적과 관련된 기능을 제공합니다.
  • class 메소드
    타입 메소드는 특정 타입 자체에 호출해서 사용 가능하고 static class 메소드가 있습니다.
    class 메소드는 클래스에서만 사용 가능하며 구조체, 열거형에서는 사용이 불가합니다.
    static 키워드는 서브 클래스에서 override 불가능하고 class 메소드는 가능합니다.

11) class 메소드와 static 메소드의 차이점을 무엇인가요?

class 메소드는 클래스에서만 사용 가능하며 구조체, 열거형에서는 사용이 불가합니다.
static 메소드는 서브 클래스에서 override 불가능하고 class 메소드에서는 가능합니다.

12) Delegate 패턴을 활용하는 경우를 예를 들어 설명하시오.

Protocol을 이용하여 권한을 위임하고 일을 처리하는 방식의 디자인 패턴입니다.
즉 Delegate 패턴은 클래스나 구조체의 인스턴스에 특정 행위에 대한 책임을 다른 타입의 인스턴스에게 넘기는 방식입니다.
예를 들면, TableViewCell의 특정 버튼에 대한 액션을 ViewController로 넘겨주기 위해서 Delegate패턴을 사용합니다.

protocol BackTableViewCellDelegate: AnyObject {
	func dismissal()
}
class BackTableViewCell: UITableViewCell {
	...
    weak var delegate: BackTableViewCellDelegate?
    
    private var dismissButton: UIButton = {
    	let button = UIButton()
        button.setTitle("뒤로", for: .normal)
        button.addtarget(self, action: #Selector(handleDismissal), for: .touchUpInside)
        return button
    }()
    
    @objc func handleDismissal() {
    	delegate.dismissal()
    }
    ...
}

class ViewController: UITableViewController {
	...
    cellForRowAt 함수 내에서 대리자 지정
    
    ...
}
extension ViewController: BackTableViewCellDelegate {
	func dismissal() {
    	dismiss(animated: true, completion: nil)
    }
}

13) Singleton 패턴을 사용하는 경우를 예를 들어 설명하세요.

싱글톤 패턴은 특정 용도로 객체를 하나 생성해서 공용으로 사용하고 싶을 때 사용하는 디자인 패턴입니다.
로그인 정보, 유저 정보, 환경 설정 등의 정보를 저장하는 용도에 주로 사용됩니다.
한번의 instance만 생성하므로 메모리 낭비를 방지할 수 있습니다.
다만 싱글톤 패턴이 너무 많은 일을 하거나 많은 데이터를 공유시킬 경우 결합도가 높아져 객체 지향 설계 원칙에 위배될 수 있습니다.

14) KVO 동작 방식에 대해 설명하세요.

Key-Value Observing의 약자.
객체의 변경사항을 다른 객체에 알리기 위해 사용하는 코코아 프로그래밍 패턴입니다.
Model, View와 같이 논리적으로 분리된 파트간의 변경사항을 전달하는데 유용합니다.
NSObject를 상속한 클래스에서만 KVO를 사용할 수 있습니다.

class UserInfo {
	var name: String
    
    init(name: String) {
    	self.name = name
    }
}

여기서 UserInfo의 name프로퍼티가 변경하는 걸 다른 객체에 알리고 싶을 때
name 프로퍼티 앞에 @objc dynamic을 선언해 줍니다.
또한 NSObject를 상속해야만 사용할 수 있기에 class 에서만 사용 가능합니다.

class UserInfo: NSObject {
	@objc dynamic var name: String
    
    init(name: String) {
    	self.name = name
    }
}

이후 Observer를 정의합니다.
var userInfo = UserInfo(name: "DevelopRecord")
userInfo.observe(.name, options: [.old, .new]) { object, change in
print(change.oldValue, change.newValue)
}
userInfo.name = "이것이 KVO"

// 출력 결과
Optional("DevelopRecord"), Optional("이것이 KVO")

참조 레퍼런스

https://github.com/JeaSungLEE/iOSInterviewquestions
https://haningya.tistory.com/217
https://zeddios.tistory.com/

감사합니다! (_ _)

0개의 댓글