API를 호출하기 위한 방법을 찾던 중, Alamofire 라이브러리가 있지만 라이브러리 말고 스스로 적용해서 불러오는 방법에 익숙해진 후 라이브러리를 사용하는게 좋을거 같다고 판단하여 관련 내용을 정리

URLSession

  • URLSession 은 위 사진과 같은 구조를 갖는다
    • URLSessionConfiguration 을 통해 URLSession을 결정한후, Session을 생성
    • Delegate는 URLSession 통신의 중간 과정이나 통신 종료 후 같은 이벤트를 확인할 때 주로 사용
    • URLSessionConfiguration을 통해 Session 을 설정하면 URLSessionTask 로 보내 통신을 시작

URLSessionConfiguration

  • URLSessionConfiguration의 종류에 대해 알아보자
    • Default : 기본적인 세션으로 쿠키나 캐시를 저장할때 사용 ( 가장 기본적인 통신 )
    • Ephemeral : 쿠키나 캐시를 저장하지 않는 통신을 할때 사용 ( Private 모드 )
    • Background : 앱이 Background 상태일 때 사용하는 통신
  • Configuration 을 적용하지 않고 shared 를 사용할 수 있다
    • shared를 사용하면 싱글톤 객체를 제공하는데 편하게 사용할 수 있는 장점이 있지만, delegate도 없고, configuration 도 없기 때문에 일부 제한이 있음 이러한 사항을 고려하지 않을때는 간편하게 사용 가능

URLSessionTask

  • Session 작업 하나를 나타내는 추상 클래스
  • Task의 종류
    • DataTask : 서버로부터 응답 데이터를 받아 Data객체를 가져오는 작업 수행
    • UploadTask : 서버에 Data 객체나 File 데이터를 올리는(Upload) 작업 수행
    • DownloadTask : 서버로부터 Data를 다운받아 File 형태로 저장하는 작업 수행 ( Background 가능 )

Concurrent (동시성) 이란 무엇인가?

  • 앱의 로직 내에서 특정 부분이 동시에 또는 임의 순서대로 실행되기 위해 필요한 개념
  • 앱의 전반적인 효율성 측면에서도 필요하지만, 앱을 사용하는 유저에게도 일관적인 UI를 그리기 위해서도 필요한 개념
  • ⇒ 네트워크 통신을 통해 어떠한 리소스를 다운받는 동안 동시성을 적용하지 않아 유저가 비어있는 화면만 바라보게 된다면 지루함을 느끼고, 짜증을 유발할 수 있다, 이때 동시성을 적용하여 네트워킹을 통해 리소스를 다운받는 동안 유저에게 특정 뷰를 그려주면 유저 입장에서도 매우 좋다
  • 데이터 흐름을 정확히 유지하는 것이 중요하기 때문에 동시에 이루어지는 두 작업이 하나의 데이터를 조작하면 안됨

GCD (Grand Central Dispatch)

  • DispatchQueue 에 등록된 작업들을 사용 가능한 스레드에 스케쥴링 API
  • Serial DispatchQueue 와 Concurrent DispatchQueue 로 나뉨
  • Serial queue ⇒ queue의 작업을 오직 하나의 스레드에서만 수행
  • Concurrent queue ⇒ 여러 스레드의 작업을 동시에 수행

동기와 비동기

  • Sync 와 Async 로 동기 및 비동기를 설정할 수 있다.
  • 동기적으로 설정된 작업은 해당 작업이 반환(종료)되기 전까지 다른 작업을 수행하지 않는다
  • 비동기적으로 설정된 작업은 해당 작업이 수행되는 동안 다른 작업을 동시에 수행하며, 작업이 종료되는 즉시 반환한다
  • 의문점.. → Serial queue / Sync 와 Concurrent queue / Async 의 차이가 뭐지?...

 https://cskime.tistory.com/18

Seiral/Concurrent는 요청된 여러 개의 작업들을 순차적으로 또는 동시에 처리 하는 경우
Sync/Async는 어떤 작업에 대한 요청과 응답이 한 번에 또는 따로 발생 하는 경우
Serial/Concurrent는 '다수의 대상에 대한 '순서'가 주된 개념
Sync/Async는 단일 작업에 대한 요청과 응답(결과)의 발생 시점이 주된 개념

 

DispatchQueue 의 종류

Main Queue

  • 앱의 시작과 동시에 생성되며 Serial Queue로 존재한다 메인큐는 반드시 UI를 위해서만 사용해야 하며 언제나 비동기적으로 작업을 수행한다
  • DispatchQueue.main.async { task }

Global Queue

  • Concurrent Queue 로 존재
  • QoS 파라미터를 가지며, 해당 파라미터에 따라 중요 순서도가 결정됨
    • QoS 종류
      • userInteractive : 사용자화 직접 상호작용 하는것들 ( UI 업데이트 , 애니메이션 등등 )
      • userInitated : 이벤트 발생 시 즉각적인 결과가 필요한 작업
      • Default : 일반적인 작업 ( global() 은 QoS 파라미터를 생략할수 있기 때문에 굳이 디폴트를 사용하진 않음 )
      • utility : progress bar 와 같이 길~게 싱행되는 작업들 ( 데이터 다운로드 등등 )
      • background : 유저가 인지할 필요가 없는 시간과 관계없는 작업들 ( 동기화 , 백업 등,, 악용하면 이걸로 정보탈취..? )
      • unspecified : 거의 사용되지 않는 파라미터로, QoS 정보가 없을때 사용
  • DispatchQueue.global(qos: 1~6의 qos 또는 생략 가능).sync/async { task }

Custom Queue

  1. 커스텀으로 큐를 구성할 때 사용
  2. 기본적으로 Serial 특성을 갖긴 하지만, 설정을 통해 Concurrent 로 사용 가능
// serial 커스텀 큐 ( 기본값 )
let customSerialQueue = DispatchQueue(label: "customSerial")

// concurrent 커스텀 큐 ( 애트리뷰트 설정을 해야함 ) , qos 알아서 추론
let customConcurrentQueue = DispatchQueue(label: "customConcurrent", attributes: .concurrent)

// concurrent 커스텀 큐에 qos 설정
let customConcurrentQueue = DispatchQueue(label: "customConcurrent", qos: .background, attributes: .concurrent)

 

참고 링크

https://hyunsikwon.github.io/ios/iOS-Concurrency-01/#gcd

https://engineering.linecorp.com/ko/blog/about-swift-concurrency/

https://sujinnaljin.medium.com/ios-차근차근-시작하는-gcd-5-c8e6eee3327b

패스트 캠퍼스 All in one_iOS 강의

DTO 와 VO 의 차이

API를 호출하고자 하는데 데이터 정의를 어떻게 해야 할지 고민이 되어 찾아보다가 관련 개념을 정리

우선, DTO 와 VO 둘다, 데이터를 정의하는데 의미가 있다 그렇다면 차이가 뭘까?

간단히 설명하면 getter 와 setter를 모두 포함하는지, getter만 포함하는지에 대한 차이가 있다.

즉, 읽기 전용 데이터인지? 적절한 수정을 통해 가공해야 하는 데이터인지에 대한 차이이다.

DTO : Data Transfer Object

⇒ getter 와 setter를 모두 가지고 있는 객체를 의미

Swift의 문법중 ‘연산 프로퍼티' 의 개념과 동일하다, 데이터를 가져와 적절히 가공하고 사용해야 할때 사용되는 개념

  • 데이터 자체를 사용하는것이 아닌, 가공 또는 한곳에 모아 사용해야 할때 사용
  • 데이터를 어딘가에 ( 외부로 ) 전송해야 할때 유용한 객체
class Greeting {
    private var korean = "안녕하세요"
    private var english = "Hello"
    
    func getKorean() -> String {
        return korean
    }
    
    func setKorean(_ korean: String) {
        self.korean = korean
    }
    
    func getEnglish() -> String {
        return english
    }
    
    func setEnglish(_ english: String) {
        self.english = english
    }
}

VO : Value Object

  • 데이터 그 자체로 의미 있는 값을 가지는것
  • DTO와 달리, getter만 가질수 있으므로 읽기 전용 객체가 된다
open class UIColor : NSObject, NSSecureCoding, NSCopying {

    //...
    open class var black: UIColor { get } // 0.0 white
    open class var darkGray: UIColor { get } // 0.333 white
    open class var lightGray: UIColor { get } // 0.667 white
    open class var white: UIColor { get } // 1.0 white
    open class var gray: UIColor { get } // 0.5 white
    open class var red: UIColor { get } // 1.0, 0.0, 0.0 RGB
    open class var green: UIColor { get } // 0.0, 1.0, 0.0 RGB
    open class var blue: UIColor { get } // 0.0, 0.0, 1.0 RGB
    open class var cyan: UIColor { get } // 0.0, 1.0, 1.0 RGB
    open class var yellow: UIColor { get } // 1.0, 1.0, 0.0 RGB
    open class var magenta: UIColor { get } // 1.0, 0.0, 1.0 RGB
    open class var orange: UIColor { get } // 1.0, 0.5, 0.0 RGB
    open class var purple: UIColor { get } // 0.5, 0.0, 0.5 RGB
    open class var brown: UIColor { get } // 0.6, 0.4, 0.2 RGB
    open class var clear: UIColor { get } // 0.0 white, 0.0 alpha
    //...
}
  • 대표적으로 UIColor 가 VO 이다.
  • color 를 사용할때 .green 을 사용하면, green 색상을 바로 읽어 올수 있다.

참고 : 링크

iOS 공부하면서 스토리보드에서 컴포넌트를 끌어다 놓을때

strong / weak 의 연결을 하는것을 알게되었고 이게 무슨의미인가.. 싶었지만

그냥 weak으로 해라! 라고만해서 그 의미에 대해 깊게 파악해보진 않았던거 같다..

그래서 이 강한참조 / 약한참조 의 근본(?)인 ARC 를 공부해보쟈!

 

What is ARC?

ARC 는 Automatic Reference Counting의 약자다!

ARC는 메모리를 스스로 관리하는 기능을 수행한다 일반적으로 Swift가 자동으로 ARC를 이용해 메모리를 관리하기 때문에 사용자는 메모리는 어떻게 처리해야하는지 깊게 생각할 필요는 없다고.. (공식문서에 써있다..)

💡 Objective-C 에서는 MRC 라고 하는 수동 메모리 관리 기법을 사용하였다, Objective-C 에서는 수동으로 관리해야 하기 때문에
retain / release 를 사용해 사용수의 증가/감소 를 확인하여 메모리를 관리하였는데 ARC 로 넘어오면서 이걸 자동으로 해준다! 그래서 프로그래머는 더이상 메모리관리에 관한 코드를 따로 작성하지 않아도 된다! 

그래서 ARC 어떻게 동작하는데?

Class 의 인스턴스가 생성될때마다, ARC는 해당 인스턴스에 대한 정보를 저장하는 Memory 할당하게 된다!

이 메모리는 당연히 인스턴스의 method, property 의 값 등의 정보를 가지고있다!

 

그리고 해당 인스턴스가 더이상 필요가 없어지면 해당 메모리를 확보하여 다른 목적으로 사용가능케한다!!

그러니까.. 한마디로 요약하면 “ Class가 필요 없어지면 해당 메모리를 해제함

 

그럼.. Class가 필요한지 필요없는지 어떻게 판단하게될까..? 이름에서 유추할수 있다!

해당 Class의 인스턴스가 참조되고 있는 수를 세어 가지고 있다!

이 수를 세기위해 클래스 인스턴스를 할당할 때마다 강력한(Strong) 참조를 하게되며, 이 강력한 참조가 유지되는 동안은 할당 해제를 허용하지 않게된다!

백문이 불여일견 직접 예시로 살펴보자

class OS {
    let kind: String
    
    // 초기화
    init(kind: String) {
        self.kind = kind
        print("[인스턴스 생성] 현재 운영체제는 \\(kind)")
    }
    
    // 소멸자
    deinit {
        print("[인스턴스 할당 해제] \\(kind) 운영체제 종료")
    }
}

일단.. Class를 맹글어 주고..

var os1: OS?
var os2: OS?
var os3: OS?

이렇게 하면 인스턴스가 생성이!!!!

안됩니다.

예 안돼요..

 

Optional 로 선언되어 있어서 기본적으로 nil 값이 할당되기 때문에 class 인스턴스를 할당하지 않아요!

os1 = OS(kind: "MacOS")
// [인스턴스 생성] 현재 운영체제는 MacOS

이제야 비로소 인스턴스가 할당되었습니다! 그러면 ARC에 의해 강한 참조로 os1 변수가 counting 될거에요!

os2 = os1
os3 = os1

이렇게 선언하면 강한참조로 counting이 2개더 더해지겠죠?!

 

자 그럼 할당을 해재해 볼거에요 우리는 할당을 해제하면서

print("[인스턴스 할당 해제] \\(kind) 운영체제 종료") 구문이 수행되기를 원합니다!

os1 = nil
os2 = nil

2개의 변수를 할당 해제했음에도 deinit 구문이 수행되지 않습니다.. 왜일까요?!

ARC에 의해 os3 에대한 reference count 를 가지고 있기 때문입니다!!

os3 = nil
// 인스턴스 할당 해제] MacOS 운영체제 종료

비로소 참조 수가 0이 되면서 deinit 이 수행된다!!

 

하지만 ARC를 사용하면서 메모리 누수 가 발생하는 상황이 반드시 나온다!

이를 방지하기 위해서 우리는 weak  unowned 의 개념을 알아야한다!

MVC 패턴의 개요

Model - View - Controller 구조로 이루어진 디자인 패턴을 의미한다.

 

Model : 앱의 데이터 또는 비즈니스 로직을 소유 ( 데이터의 변수 및 상수 , 데이터 값의 계산 등을 수행 )

View : 사용자에게 데이터 또는 UI 를 보여주는 역할을 수행 ( Storyboard 가 View 에 포함 )

Controller : Model  View 의 중간에서 View로부터 사용자의 이벤트를 감지하고, 해당 이벤트 처리를 Model에게 지시하며, Model의 계산된 데이터를 받아 View에게 전달하는 역할을 수행 ( TableViewController , ViewController, 등등.. )

 

Model - View - Controller 는 각각 어떻게 소통을 하나?

음식점을 예로 들어보자

1. 손님은 음식을 주문하기 위해 음식점의 홀에 있는 종업원에게 음식을 주문한다.
2. 음식 주문을 받은 종업원은 주방장에게 주문 내역을 보여준다.
3. 주방장은 주문내역을 보며 음식을 조리하여 조리가 완료되면 종업원을 다시 부른다.
4. 종업원은 해당 음식을 손님에게 제공한다.
5. 만약, 음식의 맛이 이상하거나 추가적인 조리를 원한다면 손님은 종업원을 호출한다.
6. 종업원은 손님의 요구사항을 적어 주방장에게 전달한다.
7. 주방장은 손님의 요구사항대로 음식을 재 조리하여 종업원을 부른다.
8. 종업원은 손님에게 재 조리된 음식을 제공한다.

자! 이제 종업원을 Controller로, 손님을 View로, 주방장을 Model 로 생각해보자

손님(View)은 요구사항을 전달하기 위해 종업원(Controller)에게 요구사항을 알려준다.

종업원(Controller)는 해당 요구사항을 주방장(Model)에게 전달한다.

주방장(Model)은 요구사항대로 조리가 되면 종업원(Controller)에게 음식을 전달한다.

종업원(Controller)주방장(Model)로부터 받은 음식을 손님(View)에게 전달한다.

즉, View  Model 은 직접적으로 소통할수 없고, Controller를 통해서만 소통을 할수 있다.

 

아주 간단한 MVC 패턴 적용 예시

TableView 를 사용해 이름들을 나열하는 화면을 그려보자!

 

일단 나 같은 경우, 공부를 해가는 과정이지만 Udemy - 안젤라유님의 강의를 듣고 최대한 습관화 하려고 노력하고있다.

이렇게 Model - View - Controller 를 구분하여 그룹으로 묶어두면 MVC패턴에 익숙해지는데 도움이 될거같아서...


Model

Name 구조체 먼저 선언해주고


View

View는 Storyboard 파일도 포함되지만, 이렇게 일부 Cell을 떼어내어 View로 구성할수 도 있다!


Controller

해당 부분을 보면 알겠지만, Model에 선언된 구조체를 Controller가 그 내용을 담고있으며,
View의 변화 ( TableView의 DataSource ) 에 따라 해당 값을 Controller가 전달한다.

 

이를 실행해보면

이와 같이 TableView 로 각 이름 값 들을 표시하는걸 볼 수 있다!

물론 해당 예시가 완벽한 MVC 패턴을 그리고 있진 않지만 대략적으로 이렇게 사용된다고 이해하면 될 것 같다!

 

 

MVC 패턴의 장점

  • 다른 패턴들에 비해 비교적 적은 코드량을 갖고있다
  • Apple 에서 SwiftUI가 나오기 전, 기본적으로 채택하고 있던 패턴요소이다! ( 하지만,, 현재는 MVVM 패턴을 강조하고 있다... MVVM 패턴은 아직까진 숙지가 되지 않아 이해하게 되면 블로그에 올릴 생각! )

 

MVC 패턴의 단점

  • 모든 일을 Controller가 맡아서 하고있다, 즉 Cotroller가 너무 많은 업무를 담당하게 된다
  • Controller의 코드가 너무 길어질 수 밖에 없는 구조! → Controller의 내부 구조가 복잡해지기 쉽다
  • 프로젝트의 규모가 커질수록 유지보수 하기에 어려움이 있다! ( 사실 아직까지 큰 프로젝트를 한적이 없어서 이 말이 잘 이해가 가지 않는다... 나중에 하게 된다면 몸소 느껴봐야겠다! )

+ Recent posts