네트워크 기본 개념
💻 네트워크란 둘 이상의 컴퓨터가 연결되고 소통하는 것을 말합니다.
💻 JSON (JavaScript Object Notation) 은 데이터를 표현하는 형식 중 하나입니다.
“이름Adam,전화번호010-1111-2222”
로 보낸다면..?“이름:Adam,전화번호:010-1111-2222”
이렇게? 🤔[
{
"name": "Adam",
"phoneNumber": "010-1111-2222"
},
{
"name": "Eve",
"phoneNumber": "010-3333-4444"
},
{
"name": "Abel",
"phoneNumber": "010-5555-6666"
}
]
[ ]
안에 3개의 전화번호부 데이터를 표현합니다.💻 API (Application Programming Interface) 란?
API 를 이해하기 위해서는 먼저 API 의 I(Interface) 가 뭔지 먼저 이해해야 합니다.
개발 용어에서 인터페이스(Interface)는 항상 창구
를 의미합니다.
너는 나의 내부가 어떻게 생겨먹었는지는 정확히 알 필요가 없어. 그저 내가 뚫어준 창구를 통해 나와 소통하면 돼.
? 예를 들어, TV 를 컨트롤 하기 위한 리모콘을 생각해봅시다.
리모콘의 전원 버튼
, 채널 버튼
, 음량 버튼
은 TV 를 컨트롤 하기 위한 창구 = API
입니다.
여러분들이 실제로 음량 버튼
내부 회로 및 하드웨어가 어떻게 동작하는지 알 필요가 있을까요?
그저 음량 버튼을 눌렀을 때
→ TV 음량이 조절된다.
의 결과가 잘 도출되는지가 중요합니다.
API Request
API Response
조금 더 실제 개발 상황을 예로 들어볼까요?
서버의 데이터베이스에 모든 유저의 정보를 담고 있습니다. 전화번호까지요.
클라이언트 (= iOS 네이티브 앱) 에서 “아담” 이라는 유저의 정보를 알고 싶습니다.
서버는 API 로 UserInfo
라는 API 를 뚫어 놓았고, 이 API 를 사용하면 유저의 정보를 알 수 있습니다. API 명세는 다음과 같습니다.
API Request
는 이렇게 보내주세요.
{
name: "Adam"
}
API Response
는 이렇게 보내주겠습니다.{
"name": "Adam",
"phoneNumber": "010-1111-2222",
"Mbti": "ENTJ"
}
API 라는 창구
를 통해서 서버와 소통을 하고, 원하는 결과를 얻으면 iOS 개발자의 책임은 끝입니다.손님
이라는 클라이언트
는 메뉴판, 웨이터
라는 창구
를 통해서 요리사
라는 서버
의 음식을 받습니다.마지막으로 API 가 뭔지 정리해보면,
Application Programming
에 필요한 Interface
입니다.프로그램을 개발
할 때 원하는 기능들을 제공해주는 창구, 설명서, 도구
입니다.🧑🏻💻 Swift 의 인코딩과 디코딩
Codable
프로토콜을 채택한다는 것은 인코딩과 디코딩이 될 수 있음을 의미.Codable
안을 열어보면 Decodable
& Encodable
로 구현되어있음.struct PhoneBook: Codable {
let name: String
let phoneNumber: String
}
Codable 을 채택함으로써 인코딩 디코딩이 가능한 객체가 됨.
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 디코딩 실패")
}
http
, https
→ 인터넷 통신 규약을 의미.google
, naver
. url 의 정체성을 나타낸다.key=value
형식으로 표현되며, 여러 개의 매개변수는 &
로 구분.🧐 예를들어, https://spartacodingclub.com
서버와 REST API 통신을 한다고 가정해봅시다.
스파르타 코딩클럽의 유저 정보 데이터들은 https://spartacodingclub.com/users
에 저장되어있다고 가정합니다. (실제로 그렇지 않습니다.)
유저 데이터를 조회하고 싶으면 GET 메소드와 해당 URL 을 사용해서 네트워크 통신을 하면 됩니다.
[
{
"id": 1,
"name": "Adam",
"email": "adam.doe@example.com"
},
{
"id": 2,
"name": "Eve",
"email": "eve.smith@example.com"
}
]
위처럼 URL 을 가지고 네트워크 통신을 할 수 있게 하는 Swift 의 클래스가 바로 URLSession 입니다.
URLSessionConfiguration
Configuration 이란 환경 설정을 의미.
URLSession
으로 네트워크 통신을 하되, 여러가지 커스텀한 설정들을 할 때 URLSessionConfiguration
을 이용.
예를들어 네트워크 통신의 타임아웃 시간 설정, 네트워크 통신 캐시 정책 설정 등을 세팅할 수 있음.
URLSession
객체를 생성하려면 URLSessionConfiguration
을 넣어줘야 함.
다음과 같이 default configuration
을 활용해 URLSession
생성 가능.
let defaultUrlSession = URLSession(configuration .default)
URLSessionTask
URLSessionTask
으로 네트워크 통신을 할 때 어떤 태스크를 수행할 것 인지 결정 가능.
URLSessionDataTask
: GET 요청. 서버로부터 데이터를 가져오거나 서버에 데이터를 전송할 때 사용.URLSessionDownloadTask
파일 다운로드를 처리할 때 사용. 백그라운드 다운로드 지원.URLSessionUploadTask
: 파일 업로드를 처리할 때 사용. 백그라운드 업로드 지원.URLSession 을 통해, 서버의 데이터를 GET 해오는 예제 코드를 작성해봅시다.
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
}
→ 서버에서 받아온 값이 잘 print 되는 것 확인.
지나칠 수 없는 썸네일이네요