iOS를 위한 네트워크 통신

호씨·2024년 12월 4일
0

네트워크 통신 이해하기

네트워크 기본 개념

네트워크란 둘 이상의 컴퓨터가 연결되고 소통하는 것을 의미한다.

다음과 같은 개념들을 알고 있어야 한다:

  • 아이폰도 하나의 컴퓨터이고, 서버도 하나의 컴퓨터로 생각할 수 있다. 따라서 서버와 아이폰의 통신도 네트워크 통신이다.
  • 인터넷은 전 세계 컴퓨터를 연결하는 거대한 네트워크를 의미한다.
  • 인터넷 연결을 위해서는 와이파이 연결이나 데이터가 켜져있어야 한다.
  • Swift로 서버와 통신하는 코드를 작성할 수 있다.

네트워크 통신 코드를 학습하기 전에, 알아야 할 기본 개념들을 먼저 살펴보도록 하자.

JSON이란?

JSON (JavaScript Object Notation)은 데이터를 표현하는 형식 중 하나이다.

예를 들어, 이름이 Adam이고 전화번호가 010-1111-2222라는 정보를 다른 누군가에게 전달할 때 어떤 포맷으로 전달하는 것이 좋을지 생각해보자.

  • 단순 문자열: "이름Adam,전화번호010-1111-2222"
  • 구분자 사용: "이름:Adam,전화번호:010-1111-2222"

네트워크에서 데이터를 주고받을 때는 정해진 형식을 지켜서 데이터를 교환하는 것이 중요하다. 이러한 형식 중 서버와 클라이언트가 가장 많이 사용하는 것이 JSON 형식이다.

JSON의 특징

  • key-value 형태를 가진다
  • 대부분의 프로그래밍 언어에서 지원한다
  • 데이터 구조를 직관적으로 표현한다

예시:

[
    {
        "name": "Adam",
        "phoneNumber": "010-1111-2222"
    },
    {
        "name": "Eve",
        "phoneNumber": "010-3333-4444"
    },
    {
        "name": "Abel",
        "phoneNumber": "010-5555-6666"
    }
]

API란?

API (Application Programming Interface)는 프로그램을 개발할 때 원하는 기능들을 제공해주는 창구, 설명서, 도구를 의미한다.

API의 이해

API를 이해하기 위해서는 먼저 API의 I(Interface)가 무엇인지 이해해야 한다. 개발 용어에서 인터페이스는 항상 창구를 의미한다.

내부 구현을 알 필요 없이 제공된 창구를 통해 소통하면 된다는 개념이다.

API 예시 (리모콘 비유)

TV를 컨트롤하기 위한 리모콘을 생각해보자:

  • 리모콘의 버튼들이 TV를 컨트롤하기 위한 창구 = API이다
  • 버튼 내부 회로나 하드웨어 동작 방식을 알 필요가 없다
  • 버튼을 눌렀을 때 → TV가 원하는 대로 동작하는 결과가 중요하다

실제 개발에서의 API

서버의 데이터베이스에 모든 유저의 정보가 있다고 가정해보자.

// API Request
{
    "name": "Adam"
}

// API Response
{
    "name": "Adam",
    "phoneNumber": "010-1111-2222",
    "Mbti": "ENTJ"
}

iOS 개발자는 이 API 명세를 보고, Request JSON과 Response JSON 형식을 지켜서 서버와 소통하는 코드를 작성하면 된다.

Swift Codable

Swift의 인코딩과 디코딩에 대해 알아보자.

주요 개념

  • 인코딩: 데이터를 특정 형식으로 변환하는 것
  • 디코딩: 인코딩된 데이터를 다시 원본으로 변환하는 것
  • Codable = Decodable & Encodable

Swift의 Codable 프로토콜을 채택한다는 것은 인코딩과 디코딩이 가능함을 의미한다.

예시 코드:

struct PhoneBook: Codable {
    let name: String
    let phoneNumber: String
}

JSON 디코딩 예제

import Foundation

struct PhoneBook: Codable {
    let name: String
    let phoneNumber: String
}

let jsonString = """
[
    {
        "name": "Adam",
        "phoneNumber": "010-1111-2222"
    },
    {
        "name": "Eve",
        "phoneNumber": "010-3333-4444"
    }
]
"""

let jsonData = jsonString.data(using: .utf8)!
let jsonDecoder = JSONDecoder()

do {
    let phoneBooks = try jsonDecoder.decode([PhoneBook].self, from: jsonData)
    for phoneBook in phoneBooks {
        print("name: \(phoneBook.name), phoneNumber: \(phoneBook.phoneNumber)")
    }
} catch {
    print("JSON 디코딩 실패")
}

URL 구조

URL(Uniform Resource Locators)은 웹에서 특정 위치를 나타내는 주소를 의미한다.

URL 구성요소

  • Protocol: http, https → 인터넷 통신 규약을 의미한다
  • Domain: 자원이 위치한 서버(컴퓨터)의 이름이다. 예를 들어 google, naver와 같이 url의 정체성을 나타낸다
  • Port: 구체적으로 어떤 서버를 이용할지 번호로 결정한다. HTTP는 80, HTTPS는 443을 사용한다
  • Path: 서버에서 제공하는 자원의 경로를 나타낸다
  • Query: 자원에 대한 추가적인 매개변수를 전달하는 데 사용된다
  • Fragment: 자원 내에서 특정 부분을 가리킬 때 사용한다

REST API

REST API(Representational State Transfer)는 전세계에서 가장 널리 사용되는 API 형식 중 하나이다.

주요 특징

  • 상태(State)를 표현해서 정보를 주고 받는 API이다
  • HTTP URL을 통해서 자원을 명시한다
  • HTTP Method를 통해 해당 자원을 어떻게 처리할지 결정한다
    • GET: 자원을 조회한다
    • POST: 자원을 생성한다
    • PUT: 자원을 업데이트한다
    • DELETE: 자원을 삭제한다

REST API 예시

GET https://spartacodingclub.com/users

응답:
[
    {
        "id": 1,
        "name": "Adam",
        "email": "adam.doe@example.com"
    },
    {
        "id": 2,
        "name": "Eve",
        "email": "eve.smith@example.com"
    }
]

URLSession

URLSession은 Swift에서 서버와 통신하기 위해 제공되는 클래스이다.

주요 구성요소

  1. URLSessionConfiguration
    • Configuration이란 환경 설정을 의미한다
    • URLSession으로 네트워크 통신을 할 때 커스텀한 설정이 필요하다
    • 네트워크 통신의 타임아웃 시간, 캐시 정책 등을 설정할 수 있다
  2. URLSessionTask
    • URLSessionDataTask: GET 요청으로, 서버로부터 데이터를 가져오거나 전송할 때 사용한다
    • URLSessionDownloadTask: 파일 다운로드를 처리하며, 백그라운드 다운로드를 지원한다
    • URLSessionUploadTask: 파일 업로드를 처리하며, 백그라운드 업로드를 지원한다

URLSession 사용 예제

import UIKit

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        fetchData()
    }
    
    private func fetchData() {
        let defaultUrlSession = URLSession(configuration: .default)
        
        guard let url: URL = URL(string: "https://reqres.in/api/users/1") else {
            print("URL is not correct")
            return
        }
        
        var request: URLRequest = URLRequest(url: url)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "Content-Type")

        let session: URLSession = URLSession(configuration: .default)

        session.dataTask(with: request) { (data, response, error) in
            let successRange: Range = (200..<300)
            
            guard let data, error == nil else { return }
            
            if let response: HTTPURLResponse = response as? HTTPURLResponse {
                print("status code: \(response.statusCode)")
                
                if successRange.contains(response.statusCode) {
                    guard let userInfo: ResponseData = try? JSONDecoder().decode(ResponseData.self, from: data) else { return }
                    print(userInfo)
                } else {
                    print("요청 실패")
                }
            }
        }.resume()
    }
}

// 데이터 모델
struct UserData: Codable {
    let id: Int
    let email: String
    let firstName: String
    let lastName: String
    let avatar: URL
    
    enum CodingKeys: String, CodingKey {
        case id
        case email
        case firstName = "first_name"
        case lastName = "last_name"
        case avatar
    }
}

struct SupportData: Codable {
    let url: URL
    let text: String
}

struct ResponseData: Codable {
    let data: UserData
    let support: SupportData
}
profile
이것저것 많이 해보고싶은 사람

0개의 댓글