🛜 네트워크 기본 개념
🧑💻 네트워크란 둘 이상의 컴퓨터가 연결되고 소통하는 것을 말합니다.
- 아이폰도 하나의 컴퓨터, 서버도 하나의 컴퓨터로 생각할 수 있기 때문에, 서버와 아이폰과의 통신도 네트워크 통신입니다.
- 인터넷이란 전 세계 컴퓨터를 연결하는 거대한 네트워크를 말합니다.
- 인터넷 연결을 위해서는 와이파이 연결이 돼있거나 데이터가 켜져있어야 합니다.
- Swift로 서버와 통신하는 코드를 작성할 수 있습니다.
- 네트워크 통신 코드를 공부하기 전에, 알아야 할 기본 개념들을 먼저 공부해 봅시다.
JSON
🧑💻 JSON (JavaScript Object Notation) 은 데이터를 표현하는 형식 중 하나입니다.
- 이름은 Adam, 전화번호는 010-1111-2222라는 전화번호 정보를 알고 있습니다. 이 정보를 다른 누군가에게 전달할 때 어떤 포맷으로 전달하는 게 좋을까요?
- 그냥 쉽게 문자열로 “이름 Adam, 전화번호 010-1111-2222” 로 보낸다면..?
- 아니면.. “이름:Adam, 전화번호:010-1111-2222” 이렇게? 🤔
- 일반적으로 데이터를 표현하는 형식이 있다면, 그걸 따르는 게 좋을 것 같습니다.
- 이렇게 네트워크에서 데이터를 주고받으려면, 아무렇게나 주고받는 것이 아니라 정해진 형식을 지켜서 데이터를 교환하는 것이 좋습니다.
- 이 중 서버와 클라이언트가 가장 많이 사용하는 데이터 형식이 JSON 형식입니다.
- JSON 은 key-value 형태를 가집니다.
- 예를 들어, 앞선 강의의 전화번호 구조체를 JSON으로 표현하면 다음과 같습니다.
[
{
"name": "Adam",
"phoneNumber": "010-1111-2222"
},
{
"name": "Eve",
"phoneNumber": "010-3333-4444"
},
{
"name": "Abel",
"phoneNumber": "010-5555-6666"
}
]
- 이 JSON 데이터는 리스트[ ] 안에 3개의 전화번호부 데이터를 표현합니다.
- JSON 은 특정한 프로그래밍 언어 안에 속하지 않으며, 대부분의 프로그래밍 언어에서는 JSON 포맷의 데이터를 다룰 수 있는 기능을 제공합니다. Swift 역시 마찬가지입니다.
API
🧑💻 API (Application Programming Interface) 란?
- API를 이해하기 위해서는 먼저 API의 I(Interface)가 뭔지 먼저 이해해야 합니다.
- 개발 용어에서 인터페이스(Interface)는 항상 창구를 의미합니다.
- 너는 나의 내부가 어떻게 생겨먹었는지는 정확히 알 필요가 없어. 그저 내가 뚫어준 창구를 통해 나와 소통하면 돼.
🧐 예를 들어, TV를 컨트롤하기 위한 리모컨을 생각해 봅시다.
- 리모컨의 전원 버튼, 채널 버튼, 음량 버튼 은 TV를 컨트롤하기 위한 **창구 = API**입니다.
- 여러분들이 실제로 음량 버튼 내부 회로 및 하드웨어가 어떻게 동작하는지 알 필요가 있을까요?
- 그저 음량 버튼을 눌렀을 때 → TV 음량이 조절된다. 의 결과가 잘 도출되는지가 중요합니다.
- 음량 버튼을 눌렀다 = API에게 내가 원하는 요청을 했다 = API Request
- 음량이 조절되었다 = API로부터 요청의 결과를 받았다 = API Response
🧑🏻💻 조금 더 실제 개발 상황을 예로 들어볼까요?
- 서버의 데이터베이스에 모든 유저의 정보를 담고 있습니다. 전화번호까지요.
- 클라이언트 (= iOS 네이티브 앱)에서 “아담”이라는 유저의 정보를 알고 싶습니다.
- 서버는 API로 UserInfo라는 API를 뚫어 놓았고, 이 API 를 사용하면 유저의 정보를 알 수 있습니다. API 명세는 다음과 같습니다.
- API Request는 이렇게 보내주세요.
{
name: "Seongpil"
}
- API Response는 이렇게 보내주겠습니다.
{
"name": "Seongpil",
"phoneNumber": "010-1111-2222",
"Mbti": "ESFJ"
}
- iOS 개발자인 여러분은 이제 이 API 명세를 보고, Request JSON과 Response JSON 형식을 지켜서 서버와 소통하는 코드를 작성하면 됩니다.
- 서버가 이 데이터를 돌려주기 위해서 내부적으로 어떤 로직을 수행했고, 서버 데이터베이스 내부가 어떻게 생겨먹었고를 알 필요가 없습니다.
- 그저 서버가 뚫어놓은 API라는 창구를 통해서 서버와 소통을 하고, 원하는 결과를 얻으면 iOS 개발자의 책임은 끝입니다.
👨🏻🍳 다시, 이번엔 레스토랑에 비유해 보겠습니다.
- 클라이언트 앱 = 레스토랑의 손님
- API = 레스토랑의 메뉴판, 웨이터
- 서버 = 레스토랑의 요리사
- 손님이라는 클라이언트는 메뉴판, 웨이터라는 창구를 통해서 요리사라는 서버의 음식을 받습니다.
- 손님이 메뉴판을 보고 웨이터를 부른다 → API 명세를 파악한다
- “봉골레 파스타 주세요” → API Request
- 요리사가 파스타를 손님에게 바친다 → API Response
🤓 마지막으로 API 가 뭔지 정리해 보면,
- API는 직역 그대로 Application Programming에 필요한 Interface입니다.
- 즉, 어떤 프로그램을 개발할 때 원하는 기능들을 제공해 주는 창구, 설명서, 도구입니다.
Swift Codable
🧑🏻💻 Swift의 인코딩과 디코딩
- 인코딩: 데이터를 특정 형식으로 변환하는 것.
- 디코딩: 인코딩 된 데이터를 다시 원본으로 변환하는 것.
- Swift 의 Codable 프로토콜을 채택한다는 것은 인코딩과 디코딩이 될 수 있음을 의미.
- Codable 안을 열어보면 Decodable & Encodable로 구현되어 있음.
- 서버와 통신하기 위해서, JSON 형식으로 인코딩을 많이 한다.
struct PhoneBook: Codable {
let name: String
let phoneNumber: String
}
- Codable을 채택함으로써 인코딩 디코딩이 가능한 객체가 됨.
🧑🏻💻 JSON 형식의 데이터에서 Swift로 데이터를 디코딩해서 추출하는 과정
import Foundation
struct PhoneBook: Codable {
let name: String
let phoneNumber: String
}
// string 으로 json 모양의 데이터를 생성.
let jsonString = """
[
{
"name": "Adam",
"phoneNumber": "010-1111-2222"
},
{
"name": "Eve",
"phoneNumber": "010-3333-4444"
},
{
"name": "Abel",
"phoneNumber": "010-5555-6666"
}
]
"""
// jsonString 으로 jsonData 를 생성.
let jsonData = jsonString.data(using: .utf8)!
// Swift 가 제공하는 JSON 디코더.
let jsonDecoder = JSONDecoder()
// JSON -> Codable 디코딩 진행.
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의 구조에 대해 자세히 공부해 봅니다.
- URL (Uniform Resource Locators): 웹에서 특정 위치를 나타내는 주소.
- Protocol: http, https → 인터넷 통신 규약을 의미.
- Domain: 자원이 위치한 서버(컴퓨터)의 이름. 예를 들어 google, naver. url의 정체성을 나타낸다.
- Port: 구체적으로 어떤 서버를 이용할지 번호로 결정. HTTP의 경우 80. HTTPS는 443.
- Path: 서버에서 제공하는 자원의 경로를 나타냄.
- Query: 자원에 대한 추가적인 매개변수를 전달하는 데 사용됨. 주로 key=value 형식으로 표현되며, 여러 개의 매개변수는 &로 구분.
- Fragment: 자원 내에서 특정 부분을 가리킬 때 사용.
- ex) https://ko.wikipedia.org/wiki/대한민국#문화
REST API
🧑🏻💻 REST API (Representational State Transfer) 란 무엇인지 공부합니다.
- 전 세계에서 대표적으로 널리 쓰이는 API 형식 중 하나.
- 상태 (State)를 표현해서 정보를 주고받는 API이다.
- HTTP URL을 통해서 자원을 명시한다.
- HTTP Method (GET, POST, PUT, DELETE 등)를 통해 해당 자원을 어떻게 할 것인지 CRUD를 결정한다.
- GET: 자원을 조회합니다.
- POST: 자원을 생성합니다.
- PUT: 자원을 업데이트합니다.
- DELETE: 자원을 삭제합니다.
- REST API 도 결국 API 이기 때문에, 데이터를 주고받는 형식, 창구라고 생각할 수 있음.
🧐 예를 들어, https://spartacodingclub.com 서버와 REST API 통신을 한다고 가정해 봅시다.
스파르타 코딩클럽의 유저 정보 데이터들은 https://spartacodingclub.com/users에 저장되어 있다고 가정합니다. (실제로 그렇지 않습니다.)
유저 데이터를 조회하고 싶으면 GET 메서드와 해당 URL을 사용해서 네트워크 통신을 하면 됩니다.
요청 방식: GET https://spartacodingclub.com/users
응답:
[
{
"id": 1,
"name": "Adam",
"email": "adam.doe@example.com"
},
{
"id": 2,
"name": "Eve",
"email": "eve.smith@example.com"
}
]
위처럼 URL 을 가지고 네트워크 통신을 할 수 있게 하는 Swift의 클래스가 바로URLSession입니다.
URLSession
🧑🏻💻 URLSession 은 Swift에서 서버와 통신하기 위해 제공되는 클래스.
- URLSession을 다루기 위해서는 크게 아래 2가지 개념을 알아야 합니다.
- URLSessionConfiguration
- URLSessionTask
1. URLSessionConfiguration
Configuration 이란 환경 설정을 의미.
URLSession으로 네트워크 통신을 하되, 여러 가지 커스텀한 설정들을 할 때 URLSessionConfiguration을 이용.
예를 들어 네트워크 통신의 타임아웃 시간 설정, 네트워크 통신 캐시 정책 설정 등을 세팅할 수 있음.
URLSession 객체를 생성하려면 URLSessionConfiguration을 넣어줘야 함.
다음과 같이 default configuration을 활용해 URLSession 생성 가능.
let defaultUrlSession = URLSession(configuration .default)
2. URLSessionTask
URLSessionTask으로 네트워크 통신을 할 때 어떤 태스크를 수행할 것 인지 결정 가능.
- URLSessionDataTask: GET 요청. 서버로부터 데이터를 가져오거나 서버에 데이터를 전송할 때 사용.
- URLSessionDownloadTask 파일 다운로드를 처리할 때 사용. 백그라운드 다운로드 지원.
- URLSessionUploadTask: 파일 업로드를 처리할 때 사용. 백그라운드 업로드 지원.
🧑🏻💻 URLSession을 통해, 서버의 데이터를 GET 해오는 예제 코드를 작성해 봅시다.
- https://reqres.in/api/users/1
- 위 URL 은 테스트를 위한 데이터를 내려주는 사이트입니다.
- GET 메서드를 사용해서 REST API 통신을 수행해 봅시다.
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
}
// URLRequest 설정
var request: URLRequest = URLRequest(url: url)
// GET 메소드 사용
request.httpMethod = "GET"
// json 데이터 형식임을 나타냄
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
// URLSession 생성 (기본 default 세션)
let session: URLSession = URLSession(configuration: .default)
// dataTask
session.dataTask(with: request) { (data, response, error) in
// http 통신 response 에는 status code 가 함께오는데, 200번대가 성공을 의미.
let successRange: Range = (200..<300)
// 통신 성공
guard let data, error == nil else { return }
if let response: HTTPURLResponse = response as? HTTPURLResponse{
print("status code: \(response.statusCode)")
// 요청 성공 (StatusCode가 200번대)
if successRange.contains(response.statusCode){
// decode
guard let userInfo: ResponseData = try? JSONDecoder().decode(ResponseData.self, from: data) else { return }
print(userInfo)
} else { // 요청 실패 (Status code가 200대 아님)
print("요청 실패")
}
}
}.resume()
}
}
// 데이터 구조체 정의
struct UserData: Codable {
let id: Int
let email: String
let firstName: String
let lastName: String
let avatar: URL
// JSON 키와 구조체 프로퍼티 간의 매핑을 위해 CodingKeys 열거형 정의
enum CodingKeys: String, CodingKey {
case id
case email
case firstName = "first_name"
case lastName = "last_name"
case avatar
}
}
// Support 구조체 정의
struct SupportData: Codable {
let url: URL
let text: String
}
// 최상위 구조체 정의
struct ResponseData: Codable {
let data: UserData
let support: SupportData
}
'스파르타 코딩 클럽 - iOS 스타터 6기 > 본 캠프' 카테고리의 다른 글
34. 스파르타 코딩 클럽 - 포켓몬 연락처 앱 만들기 (1) (1) | 2025.04.17 |
---|---|
33. 스파르타 코딩 클럽 - 날씨 앱 만들기 (0) | 2025.04.16 |
31. 스파르타 코딩 클럽 - CoreData와 UserDefaults (0) | 2025.04.15 |
30. 스파르타 코딩 클럽 - 메모리 관리 이해 (1) | 2025.04.14 |
29. 스파르타 코딩 클럽 - ViewController 생명주기 (1) | 2025.04.14 |