iOS 개발자 기술 면접 준비

JSLee·2022년 6월 14일
1

👦🏻 기술 면접

많은 개발자 들은 깃허브, 개인 블로그, 포트폴리오 등등 취업을 위해 자신의 소양을 밝힐수 있는
매개체를 많이 준비 해야 됩니다.
이러한 것들로 인해 서류전형이 합격되고 면접으로 이어질수 있기 때문이죠

이번엔 신입 iOS Developer 이 기술면접 에서 자주 받는 질문 + 제가 면접을 다니며 받았던 질문을 토대로
기술 면접 에 대비한 포스팅을 남기려고 합니다.

가장 기본적인 질문 List

1. View Controller, View의 생명주기에 대해 설명하세요.

제가 생각 했을때 토이 프로젝트, 포트폴리오 앱 을 개발을 하셨다면
이 사진을 봤을때 금방 이해 하실꺼라 생각합니다.

ViewController 의 Lifecycle 의 경우 크게 이렇게 돌아간다고 생각하시면 됩니다.
하지만 이 밖에도 viewDidLayoutSubviews, viewWillLayoutSubviews Layout 잡기 시작 과 끝 시점을 관리할수 있는 메서드도 존재 합니다.

  • init
    View 객체가 생성 됩니다.

  • loadView
    View 가 메모리 에 load 됩니다.
    메소드의 직접 호출은 X
    이유 확인

  • viewDidLoad
    View 가 메모리에 load 되었을때 자동으로 Call 되는 Method
    화면이 처음 만들어 질때 1회 실행 되기 때문에 초기화 코드를 작성하는것이 용이 합니다.

  • viewWillAppear
    root View 가 Load 된 후 Window 로 올라가기 전 Call 되는 Method
    ViewController 전환시 다시 되돌아 오는 경우 발생하는 Event 는 이 Method 에 작성하는것이 좋다.
    viewWillAppear와 viewDidAppear사이에 constraint와 layout이 적용된다.

  • viewDidAppear
    window 의 root view가 View 계층으로 더해진 직후 호출되는 메서드 입니다.
    View가 나타났다는 것을 컨트롤러에게 알리는 역할을 합니다. 또한 화면에 적용될 애니메이션을 그려줍니다.

  • viewWillDisappear
    window 의 root view가 View 계층에서 제거되기 직전 호출되는 메서드입니다.
    View가 삭제되려고 하는 것을 ViewController에 통지합니다.

  • viewDidDisappear
    window 의 root view가 View 계층에서 제거된 직후 호출되는 메서드 입니다.
    view가 제거되었음을 알려줍니다

  • viewDidUnload
    View가 메모리에서 해제된 뒤 호출됩니다.

2. App의 생명주기에 대해 설명하세요.

app의 생명 주기는 App의 실행 / 종료 및 App이 Foreground / Background 상태에 있을 때,

시스템이 발생시키는 Event에 의해 App의 상태가 전환되는 일련의 과정을 뜻합니다.

Foreground : 앱이 화면에 올라와있는 상태

Background : 앱이 화면상에서 보여지지 않는 상태

- Not running

App 이 실행되지 않았거나, 완전히 종료되어 동작하지 않는 상태

- Foreground

앱이 전면에서 실행되고 있는 상태

  • Inactive
    앱이 실행되면서 foreground에 진입하지만, 앱 실행 중 미리알림 또는 일정 Alert 이 화면에 덮여서 App이 실질적으로는 Event를 받지 못하는 상태

앱의 상태 전환 과정에서 잠깐 머무는 단계

전화가 왔을 때, 시스템 메시지가 떴을 때 (예 : 배터리 부족)

  • Active

앱이 실행 중이며, foreground에 있고, 이벤트를 받고 있는 상태

어플리케이션이 실질적으로 활동하고 있는 상태

- Background

앱이 백그라운드에 있으며, 다른 앱으로 전환되었거나 홈 버튼을 눌러 밖으로 나갔을 때의 상태

  • Background 상태로 실행되는 app은 inactive 대신 background 상태로 진입

  • Suspended 상태가 되기 전 잠깐 머무는 상태(추가 코드 실행이 필요하면 머무는 시간 연장)

  • 코드가 실행중이지만 사용자의 이벤트를 받을 수는 없음 추가적인 코드 (ex. 파일 다운로드)를 실행하는 동안 머무름

  • 홈버튼을 두번 눌러 앱을 다시 열었을 때, 처음부터 재실행되지 않는다면 background 상태에 있다가 올라온 것

ex) background에서 음악을 재생하거나 거리를 추적하고 있는 상황

- Suspended

앱이 Background 상태에 있지만, 아무 코드도 실행하지 않은 상태입니다.

백그라운드에서 특별한 작업이 없을 경우 Suspended 상태가 됩니다.

이 상태에서 앱은 메모리상에 올라가있지만 아무 일도 하지 않기 때문에 배터리를 사용하지 않습니다.

또한 OS에 의해 메모리 부족 현상이 발생하면 이 상태의 앱은 메모리에서 없어질 수 있으며, 이는 따로 알림을 하거나 하진 않습니다.

AppDelegate 객체의 메소드 호출

- 1. Not Running 상태일 때

application(_:willFinishLaunchingWithOptions:)

앱을 실행할 때 최초로 실행할 코드를 작성하면 좋으며, 필요한 주요 객체들을 생성하고 앱 실행 준비가 끝나기 직전에 호출됩니다.

application(_:didFinishLaunchingWithOptions:)

앱이 최초로 실행될 때 호출되는 메소드이며, 앱 실행을 위한 모든 준비가 끝난 후 화면이 사용자에게 보여지기 직전에 호출됩니다.

App이 실행 직후 화면이 사용자에게 보여지기 직전에 호출
초기화 코드 작성
App이 최초 실행될 때 호출되는 메소드
Not Running -> Foreground 로 상태 변환

applicationWillTerminate(_:)

앱이 종료되기 직전에 호출됩니다. (단, suspend 상태에서는 호출되지 않음)

App이 종료되기 직전에 호출
다음 경우에는 호출되지 않음
메모리 확보를 위해 Suspended 상태에 있는 app을 종료시킬 때
사용자가 multitasking UI를 통해 종료할 때
오류로 인해 app이 종료될 때
Deivce를 재부팅할 때

- 2. In - Active 상태일 때

applicationWillEnterForeground

Background -> Foreground로 전이될 때 실행

App이 Background에서 Foreground로 돌아오기 직전, 화면에 보여지기 직전 호출
호출된 뒤 Inactive 상태를 거쳐 Active 상태로 진입

applicationWillResignActive

Active -> InActive 상태로 전이될 때 실행

App이 Inactive 상태로 전환되기 직전 호출

sceneWillEnterForeground(_:)

앱이 background나 not running에서 foreground로 들어가기 직전에 호출

비활성화 상태를 거쳐 활성화 상태가 됨

앱이 background에서 foreground로 이동 될 때 실행 ( 아직 foreground에서 실행중이진 않음)

sceneWillResignActive(_:)

App Switcher 모드(홈 바 쓸어 올렸을 경우 또는 홈 버튼 모델 홈 버트 두번 눌렀을 경우)

앱이 active에서 inactive로 이동될 때 실행
Active -> InActive 상태로 전이될 때 실행
App이 Inactive 상태로 전환되기 직전 호출

- 3. Active 상태일 때

applicationDidBecomeActive

Active될 때 실행

App이 Active 상태로 전환되어 화면이 나타난 후 직후 호출
Inactive 상태로 넘어가 중지된 작업을 여기서 반드시 재실행시켜줘야 함 ex) 화면 갱신 등

sceneDidBecomeActive(_:)

앱이 비활성화 상태에서 활성 상태로 진입하고 난 직후 호출

앱이 실제로 사용되기 전에 마지막으로 준비할 수 있는 코드를 작성
앱이 active 상태가 되어 실행 중일 때 실행

- 4. Background 상태일 때

applicationDidEnterBackground

앱이 background 상태일 때 실행

App이 Background 상태로 전환된 직후 호출
Background 상태에서 Suspended 상태로 전환
App이 언젠가 종료될 것임을 뜻하기 때문에 중요한 사용자 데이터를 저장하거나, 공유 자원을 해제하는 등의 작업 수행 필요
App이 재실행될 때 직전 상태를 복구할 수 있는 정보를 저장하는 코드

sceneDidEnterBackground(_:)

앱이 background 상태로 들어갔을 때 호출

suspended 상태가 되기 전 중요한 데이터를 저장하는 등 종료하기 전 필요한 작업을 함
Background -> Foreground로 전이될 때 실행

- 5. suspended 상태일 때

따로 호출되는 메소드는 없으며 background 상태에서 특별한 작업이 없을 때 이 상태가 됩니다.


3. scene delegate, app delegate 에 대해 설명하세요.

iOS12까지는 대부분 하나의 앱에 하나의 window였지만 iOS 13부터는 window의 개념이 scene으로 대체되고 아래의 사진처럼 하나의 앱에서 여러개의 scene을 가질 수 있습니다.

그리고
AppDelegate 에서 UILifeCycle 에 대한 부분이 SceneDelegate 로 넘어 갔습니다.

SceneDelegate 에서 UI 를 관리 하게된다면
AppDelegate 는 Scene Session 을 통해
Scene 에 대한 정보를 업데이트 합니다.

또한 이밖에도 AppDelegate 는

  • App 의 데이터 구조를 초기화 합니다.
  • App 의 scene 을 configure 합니다.
  • App Background 에서 의 알림,푸쉬에 반응 합니다.
  • 특정 scene, view, view controller 에 구애 받지 않고 App 자체 이벤트에 반응합니다.

4. ARC(Automatic Reference Counting)에 대해 설명하세요.

ARC 는 자동으로 Reference Counting 을 해주는 기능 입니다.
자세한 설명은 제가 포스팅한 글을 참고 할수 있습니다.

포스팅한 게시글


5. weak와 strong, unowned에 대해 설명하세요.

위 3가지는 메모리를 참조 하는 방법 입니다.

weak (약한참조)

포인터 개념 입니다. 해당 인스턴스의 주소값만 을 가지고 있습니다.
참조 하는 인스턴스의 리테인카운트 를 증가시키지 않습니다.
메모리 해제는 다른 클래스가 담당합니다.
메모리가 해제될경우 자동으로 nil 로 초기화 됩니다.
항상 옵셔널 타입이어야 합니다.

strong (강한참조)

weak 과 반대되는 개념입니다.
선언시 아무것도 적어주지 않으면 강한참조가 됩니다.

var str = Strong() //리테인 카운트 증가 +1
str = nil //메모리 해제

unowned (미소유 참조/약한참조)

weak 과 비슷한 개념입니다.
소유권을 가지지 않고 리테인 값도 증가시키지 않습니다.
하지만 옵셔널로 선언 되지 않아야 합니다.(nil 일수 없는 객체)

weak / unowned 차이점

weak 은 객체를 계속 추적합니다. 객체가 사라지게 되면 nil 로 변경됩니다.
unowned 은 객체가 사라져도 댕글링 포인터가 남게 됩니다.
이 포인터를 참조하게 되면 crash 가 발생되고
이유는 unowned 객체는 사라지지 않는 조건이 있기 때문입니다.

댕글링 포인터 = 원래 바라보던 객체가 메모리에서 해제 되면 할당되지 않는 곳을 보는 포인터

사용

strong : strong 은 ARC 에 인해 자동으로 해제 되지 않아야 하는 객체에 사용되어야 합니다.

weak: weak 는 메모리 누수를 막기 위해 사용되고 delegate 패턴이 대표적 입니다.

unowned : unowned 는 객체의 사이클이 명확하고 개발자가 컨트롤이 가능한 경우


6. Escaping Closure에 대해 설명하세요.

이스케이핑 클로져 는 탈출 클로져 라고 이야기 합니다.

인자로 전달된 클로저가 함수의 밖의 변수에 저장되거나 함수가 종료된 뒤 실행되는 클로저를 escaping closure 라고 합니다.

또한 이스케이핑 클로져 는 비동기적 성격을 가지고 있습니다.
그렇기에 비동기적으로 진행되어야 하는 HTTP 통신에서 많이 사용되기도 합니다.

func getImage(from url: String, completion: @escaping (UIImage?) -> Void) {
    let task = URLSession.shared.dataTask(with: URL(string: url)!) { data, _, _ in
        guard let data = data, let image = UIImage(data: data) else {
            return
        }
        DispatchQueue.main.async {
            completion(image)
        }
    }
    task.resume()
}

정말 많이 사용 되는 하나의 소스코드 입니다.
이렇게 가져온 image 를 tableView Cell 에 넣어준다고 가정하면

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "MemberTableViewCell", for: indexPath) as! MemberTableViewCell
    
    getImage(from: imageURL) { image in
        cell.avatarImageView.image = image
    }
    return cell
}

이렇게 간결한 코드를 작성할수 있습니다.
만약 이스케이핑을 사용하지 않았다면 가독성 과 tableView 메소드에 너무 많은 코드가 들어가게 되며 좋지 않은 코드가 될수 있습니다.


7. 타입 캐스팅을 할 때 사용하는 키워드인 as, as?, as! 이 셋의 차이를 설명하세요.

as - 타입이 맞지 않을때 런타임 에러가 발생합니다.
as? - 타입이 맞지 않아도 에러를 발생하지 않습니다. (다운 캐스팅)
변환이 되는지 되지 않는지 알수 있습니다.

  • 다운 캐스팅: 부모클래스를 자식클래스로 변환하는 형변환

as! - 강제 언랩핑 으로 행해지는 타입캐스팅 입니다.
형변환이 되지 않아도 런타임 에러는 발생되지 않지만 실행시점에서 crash 가 일어납니다.


8. Swift에서 Class와 Struct의 차이를 설명하세요.

class

  • 참조 타입 입니다.
  • 상속이 가능합니다.
  • ARC로 메모리 관리
  • 참조 타입이기 때문에 같은 참조를 띄고 있는 클래스는 값이 공유 됩니다.
  • 타입 캐스팅을 통해 런타임에서 클래스 인스턴스의 타입을 확인 가능합니다.
  • deinit을 이용해 클래스 인스턴스의 메모리 할당을 해제할 수 있습니다.

struct

  • 값 타입 입니다.
  • 구조체 변수를 새로운 변수에 할당할 때마다 새로운 구조체가 할당 됩니다.
  • 값을 변경시키더라도 다른 변수에 영향을 주지 않습니다.
  • 상속이 불가능 합니다.

9. Frame 과 Bounds 의 차이를 설명하세요.

frame - superView 안에서 View 의 좌표를 나타냅니다.
bounds - superView 와 무관하게 자신만의 좌표를 나태냅니다.
bounds 를 통한 View 의 이동은
View 의 이동이 아닌 좌표의 이동이라고 생각할수 있습니다.



10. delegate 패턴에 대해 설명하세요.

델리게이트 패턴 은 객체가 다른 객체에게 자신의 기능을 위임하는 디자인 패턴을 말합니다.
이러한 디자인 패턴을 사용하는 이유는
코드의 재사용율을 높힐수 있기 때문입니다.

비슷한 기능을 각 객체마다 새롭게 구현해야 하는것 처럼
생산성 떨어지는 일이 없기 때문이죠.

저는 보통 A 와 B 라는 VC 간에 데이터 전달, A -> B 로 VC 의 전환이 진행된뒤 B -> A 로 다시 돌아올때
B 에서 A로 Data 가 전달되어야 할때 A에서 Data 를 전달 받으면 B 의 pop 기능을 A에서 진행하는 로직을 자주 사용했습니다.


11. Delegate vs Block vs Notification의 차이에 대해 설명하세요.

Delegate

Delegate는 프로토콜을 정의하여 사용합니다.
프로토콜은 일종의 청사진 역할을 하여 프로토콜을 채택한 곳에서는 청사진에 제시된 것들을 구현할 수 있게끔 합니다.

프로토콜에 우리가 원하는 이벤트들의 정보를 받을 수 있게끔 함수의 원형을 정의해놓고 난 뒤에, 실제뷰에서 사용하면 됩니다.

장점

매우 엄격한 Syntax로 인해서 프로토콜에 필요한 메서드들이 명확하게 명시가 됩니다.
컴파일 시 경고나 에러가 떠서 프로토콜의 구현되지 않은 메서드를 알려줍니다.
로직의 흐름을 따라가기가 쉽습니다.
프로토콜 메서드로 알려주는 것뿐만 아니라 정보를 받을 수도 있습니다.
커뮤니케이션 과정을 유지하고 모니터링하는 제 3의 객체가 필요하지 않습니다.
프로토콜이 컨트롤러 범위 안에서 정의됩니다.

단점

많은 줄의 코드가 필요합니다.
delegate 설정에 nil이 들어가지 않게 주의해야 합니다.
많은 객체들에게 이벤트를 알려주는 것이 어렵고 비효율적입니다.

Block

이벤트가 딱 하나 일 때 사용하기 좋습니다.
Block은 Closure를 지칭하는 말이기도 합니다. (익명함수)

근데 캡쳐하는 방식이 다릅니다.
캡쳐란 클로저나 블럭 안에서 사용하는 함수저장의 방식을 말합니다.
Block

Value Type : 값을 복사해서 캡쳐함. 상수로 선언되어 바꿀 수 없음.
Reference Type : 참조하여 캡쳐함. 상수로 선언되어 바꿀 수 없음.
Closure

Value Type : 참조하여 캡쳐함. 상수로 선언되어 바꿀 수 없음.
Reference Type : 참조하여 캡쳐함. 상수로 선언되어 바꿀 수 없음.
Closure는 무조건 값을 참조하여 내부에서 사용하게 됩니다.

암튼 보통 Block 을 사용하는 경우가 Completion Handler 에서 사용합니다.

Notification

NotificationCenter 라는 싱글톤 객체를 통해서 이벤트들의 발생 여부를 옵저버를 등록한 객체들에게 Notification 을 post 하는 방식을 사용합니다.

장점

짧은 코드로 구현이 가능합니다.
다수의 객체들에게 동시에 이벤트의 발생을 알려줄 수 있습니다.
Notification과 관련된 정보를 Any? 타입의 object, [AnyHashable: Any]? 타입의 userInfo 로 전달할 수 있습니다.

단점

key 값으로 Notification의 이름과 userInfo를 서로 맞추기 때문에 잘 구독이 되고 있는지 알수가 없습니다.
추적이 쉽지가 않습니다.
Notification Post이후의 정보를 받을 수가 없습니다.


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

스토리 보드를 사용하여 개발을 하였을때
장점으로는 직관적으로 UI 에 반응 할수 있습니다.

하지만 단점으로는 제가 생각했을때
스토리보드에 의존성이 올라가게 되면 기능에 따른 UI 의 변화나 코드로 레이아웃을 잡는 방법에 대해 능숙 해지지 못할수도 있다고 생각합니다.

또한 협업을 하는 와중 많은 충돌이 발생할수도 있다고 생각되어
스토리보드를 사용하지 않고 개발하고 있습니다.


13. Safearea에 대해서 설명하세요.


Apple 은 ios 11 부터 SafeArea 밖에 즉 디바이스 상단 에 있는 statusBar 와 하단에 있는 home indicator 위에 UI 컴포넌트 를 배치 하지 못하게 권고 하고 있습니다.

이유는 다양하지만 가장 중요한 이유는 디바이스에 표시되는 기능들을 방해하지 말라는 이유가 가장 크다고 합니다.


14. 코코아 프레임워크에 대해 설명하세요.

프레임 워크는 App의 뼈대를 만들어 두는 것입니다.
이런 프레임 워크를 여러개 모아 더욱 큰 프레임워크를 구성한 것이 Apple 의 프레임 워크라고 볼수 있습니다.

이중에서 터치와 관련된 기능 개발 도구가 코코아 터치 프레임워크 입니다.
UIKit 와 Foundation 프레임워크가 포함되어 있습니다.
import 하여 사용할수 있습니다.

Foundation 프레임워크는 이름 그대로 기반을 위한 도구들이 포함되어있습니다. 데이터타입, 콜렉션, OS기능 등이 포함되어있어서 macOS, iOS, watchOS 등등에 범용적으로 사용됩니다.

UIKit 프레임워크는 iOS와 tvOS를 위한 기반을 제공하여 인터페이스 그래픽을 구성하는 도구를 포함합니다.


15. 옵셔널 바인딩에 대해 설명하세요.

Swift 는 옵셔널 을 가지고 있습니다.
옵셔널 이란 쉽게 설명하여 값이 있을수도 없을수 있다. 라고 말할수 있습니다.

개발자는 데이터가 옵셔널로 랩핑되어 있는 것을 언랩핑 하여 사용하여야 합니다.

방법으로는

  • Force unwrapping : 강제 옵셔널 언랩핑
  • Optional Binding : if let, guard let을 써서 옵셔널 추출

첫번째 방법인 강제 옵셔널 언랩핑은 "!" 로 강제 해제 할수 있습니다.
하지만 이러한 방법은 좋지 않는 방법입니다.
값이 정말 확실히 있다고 하여도 사용은 하지 않는것이 좋습니다.

두번째 방법 옵셔널 바인딩은 조건문 들을 통해 만약 데이터에 값이 없을 경우를 설정해 주며 바인딩 할수 있습니다.


16. lazy 키워드에 대해 설명하세요.

lazy 키워드는 var(변수)에 만 사용할수 있습니다.
또한 struct, class 에 서만 사용 가능합니다.
클로져를 통해 값을 넣어줄수 있습니다.(self)

lazy 는 처음 사용되기 전까지는 연산이 되지 않습니다.


17. 실제 디바이스가 없을 경우 개발 환경에서 할 수 있는 것과 없는 것을 설명하세요.

디바이스 없이 시뮬레이터로 테스트를 하게 된다면 사용할수 없는 기능은 다양합니다.
제 경험을 토대로 말씀드리게 되면

첫번째로 위치기반 서비스를 사용할수 없습니다.
시뮬레이터로는 현재 움직이거나 위도, 경도 를 통한 위치 서비스를 이용할수 없습니다.

두번째로 카메라 관련 서비스를 이용할수 없습니다.

카메라 관련 서비스는 다양합니다. ARKit, QR코드, Filter 등등 사용되지 않습니다.
(하지만 시뮬레이터 갤러리에 접근하여 사진 관련 서비스는 이용 가능 합니다.)

이 밖에도 스마트폰(디바이스) 를 통한 기능들은 거의 대부분 사용 불가능 입니다.
전화, 마이크, 손가락 두개를 이용한 zoom in out, FaceID 등등이 있습니다.

그 외는
Apple의 푸시 알림 받기와 보내기를 지원하지 않습니다.

사진,연락처,캘린더에 액세스하기 위해 개인 정보 보호 알림을 지원하지 않습니다.

Handoff 기능을 지원하지 않습니다.

MessageUI 기능을 지원하지 않습니다.


🤷🏻‍♀️ 받은 질문


1. AnyObject 의 대해 설명하세요.

Any: 모든 타입의 인스턴스를 나태낼수 있습니다.
AnyObject: 모든 "클래스"타입의 인스턴스를 나태낼수 있습니다.

AnyObject 는 구조체(Struct) 가 상속 받을수 없습니다.

그렇기에 protocol 을 선언할때 AnyObject 를 상속받게 되면

class -- only protocol 이 되게 됩니다.

class 와 Anyobject 의 관계는 둘이 같은 것 입니다.

class == AnyObjcet


2. Kingfisher 라이브러리에 대해 설명하세요.


profile
iOS/Android/FE/BE

0개의 댓글