네트워크 기본 개념
네트워크란 둘 이상의 컴퓨터가 연결되고 소통하는 것을 말한다.
- 아이폰도 하나의 컴퓨터, 서버도 하나의 컴퓨터로 생각할 수 있기 때문에, 서버와 아이폰과의 통신도 네트워크 통신입니다.
- 인터넷이란 전 세계 컴퓨터를 연결하는 거대한 네트워크를 말합니다.
- 인터넷 연결을 위해서는 와이파이 연결이 되있거나 데이터가 켜져있어야 합니다.
- Swift 로 서버와 통신하는 코드를 작성할 수 있습니다. (Swift에서 기본 제공해 주는 네트워크 통신용 클래스는 URLSession)
JSON 이란
- 일반적으로 데이터를 표현하는 형식이 있다면, 그걸 따르는 게 좋을 것 같습니다.
- 이렇게 네트워크에서 데이터를 주고받으려면, 아무렇게나 주고 받는 것이 아니라 정해진 형식을 지켜서 데이터를 교환하는 것이 좋습니다.
- 이 중 서버와 클라이언트가 가장 많이 사용하는 데이터 형식이 JSON 형식입니다.
- JSON 은 key-value 형태를 가집니다. (중괄호안에 키랑 밸류값을 넣어줌)
- 예를 들어, 앞선 강의의 전화번호 구조체를 JSON 으로 표현하면 다음과 같습니다.
//JSON
[
{
"name": "Adam",
"phoneNumber": "010-1111-2222"
},
{
"name": "Eve",
"phoneNumber": "010-3333-4444"
},
{
"name": "Abel",
"phoneNumber": "010-5555-6666"
}
]
- 이 JSON 데이터는 리스트[ ] 안에 3개의 전화번호부 데이터를 표현합니다.
- JSON 은 특정한 프로그래밍 언어 안에 속하지 않으며, 대부분의 프로그래밍 언어에서는 JSON 포맷의 데이터를 다룰 수 있는 기능을 제공합니다. Swift 역시 마찬가지입니다. (JSON 인코더 디코더 스위프트에서 제공해줌)
API (Application Programming Interface)
- API 를 이해하기 위해서는 먼저 API 의 I(Interface) 가 뭔지 먼저 이해해야 합니다.
- 개발 용어에서 인터페이스(Interface)는 항상 창구를 의미합니다.
실제 개발 상황을 예로 들면
- 서버의 데이터베이스에 모든 유저의 정보를 담고 있습니다. 전화번호까지요.
- 클라이언트 (= iOS 네이티브 앱) 에서 “아담” 이라는 유저의 정보를 알고 싶습니다.
- 서버는 API 로 UserInfo 라는 API 를 뚫어 놓았고, 이 API 를 사용하면 유저의 정보를 알 수 있습니다. API 명세는 다음과 같습니다.
- API Request 는 이렇게 보내주세요.
{
name: "Adam"
}
- API Response 는 이렇게 보내주겠습니다.
{
"name": "Adam",
"phoneNumber": "010-1111-2222",
"Mbti": "ENTJ"
}
- iOS 개발자인 여러분은 이제 이 API 명세를 보고, Request JSON 과 Response JSON 형식을 지켜서 서버와 소통하는 코드를 작성하면 됩니다.
- 서버가 이 데이터를 돌려주기 위해서 내부적으로 어떤 로직을 수행했고, 서버 데이터베이스 내부가 어떻게 생겨먹었고를 알 필요가 없습니다.
- 그저 서버가 뚫어놓은 API 라는 창구 를 통해서 서버와 소통을 하고, 원하는 결과를 얻으면 iOS 개발자의 책임은 끝입니다.
마지막으로 API 가 뭔지 정리해보면,
- API 는 직역 그대로 Application Programming 에 필요한 Interface 입니다.
- 즉, 어떤 프로그램을 개발할 때 원하는 기능들을 제공해주는 창구, 설명서, 도구 입니다.
Swift Codable
🧑🏻💻 Swift 의 인코딩과 디코딩
- 인코딩: 데이터를 특정 형식으로 변환하는 것.
- 디코딩: 인코딩 된 데이터를 다시 원본으로 변환하는 것.
- Swift 의 Codable 프로토콜을 채택한다는 것은 인코딩과 디코딩이 될 수 있음을 의미.
- Codable 안을 열어보면 Decodable & Encodable 로 구현되어있음.
- 서버와 통신하기 위해서, JSON 형식으로 인코딩을 많이 한다.
struct PhoneBook: Codable {
// Codable을 책택한다는 건 Swift에서 Encodable, Decodable을 함께 채택한 거고
// 그말은 인코딩과 디코딩이 가능한 객체가 된다는 말이다.
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) // try라서 디코딩 실패할수도있음
for phoneBook in phoneBooks {
print("name: \(phoneBook.name), phoneNumber: \(phoneBook.phoneNumber)")
}
} catch {
print("JSON 디코딩 실패")
}
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 (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 = response as? HTTPURLResponse{
// 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 되는 것 확인.
'iOS (스파르타) > 앱 개발 숙련' 카테고리의 다른 글
SceneDelegate.swift (0) | 2024.07.12 |
---|---|
날씨 앱 만들기 (1) | 2024.07.11 |
CoreData 와 UserDefaults - 일단 강의만 빠르게 수강 수정예정 (0) | 2024.07.10 |
메모리 관리 이해 (2) | 2024.07.10 |
ViewController 생명주기 (1) | 2024.07.10 |