네트워크

JG Ahn·2024년 11월 8일

swift 심화

목록 보기
9/18
post-thumbnail

네트워크

  • URLSession을 사용하여 서버와 네트워크 통신을 처리
  • 앱과 서버간의 데이터 통신, API 호출 등에 사용

RESTful API

  • RestFul API란 서버와 클라이언트 간 데이터를 주고 받기 위해 표준화된 방법을 정의한 것
  • 주로 JSON이나 XML 을 통해 데이터를 주고 받으며, 의도에 맞는 HTTP 메소드를 사용
  • 주로 사용되는 HTTP 메소드
    • GET
      • 서버에서 데이터를 읽어올 때 사용
      • 쿼리스트링으로 데이터를 전달
        • URL뒤에 ?를 붙인 후 key=value 형태로 데이터를 보냄
        • 여러개의 데이터를 보낼 때는 &를 사용하여 구분
    • POST
      • 새로운 데이터 생성을 요청할 때 사용
      • Body 에 데이터를 담아서 요청
    • PUT
      • 기존 데이터를 수정하거나 업데이트 할 때 사용
      • Body 에 데이터를 담아서 요청
    • PATCH
      • 기존 데이터의 일부를 수정할 때 요청
      • Body 에 데이터를 담아서 요청
    • DELETE
      • 데이터 삭제를 요청할 때 사용

URLSession

URLSession은 서버와 네트워크 통신을 처리하는 핵심 객체

  • URLSession은 네트워크 요청을 관리하고, 네트워크 작업을 실행하며 결과를 처리
  • 비동기적으로 네트워크 요청을 보내고 응답을 받아서 이벤트를 처리

URLSession 주요 구성 요소

//기본 사용 방법
import Foundation

func fetchPosts() {
    print("Starting API Call")

    let task = URLSession.shared
    .dataTask(with: URL(string: "https://jsonplaceholder.typicode.com/posts")!) { (data, response, error) in
        
        if let error = error {
            print(error.localizedDescription)
            return
        }
        
        guard let data = data else {
            print("No data")
            return
        }
        
        // data를 사용하여 작업 진행
        print("API Success Do Something with Data")
    }
    
    task.resume() // 작업 시작

    print("API Call Started")
}

fetchPosts()
/*
API 가 호출되고 네트워크를 통해 서버에서 값을 받아오는 시간이 존재하여 
클로저가 마지막에 호출됨
*/
  • URLSessionTask
    • 위 코드에서 URLSession.shared.dataTask(...)의 반환 타입으로 서버에 데이터를 요청하는 비동기 작업을 담당
    • dataTask(with:) 메소드는 URL을 통해 데이터를 요청하고, 클로저 내부에서 서버의 응답을 처리
    • task.resume()는 실제로 네트워크 요청을 시작하는 부분
      URLSessionTask는 기본적으로 멈춘 상태에서 시작되기 때문에 resume()을 호출해줘야 작업이 진행됨
  • URLSessionConfiguration
    • 위 코드에서는 URLSession.shared를 사용하여 기본 설정을 가진 세션을 사용
    • 만약 타임아웃, 캐시 정책 등을 설정하고 싶다면, URLSessionConfiguration을 사용해 별도로 세션을 구성

Result Type

import Foundation

func divide(_ numerator: Int, by denominator: Int) -> Result<Int, Error> {
    guard denominator != 0 else {
        return .failure(NSError(domain: "나누기오류", code: 1, userInfo: [NSLocalizedDescriptionKey: "0으로 나눌 수 없어요!"]))
    }
    return .success(numerator / denominator)
}

let result = divide(10, by: 2)

switch result {
case .success(let value):
    print("Result is \(value)")
case .failure(let error):
    print("Failed with error: \(error.localizedDescription)")
}


let errorResult = divide(5, by: 0)
switch errorResult {
case .success(let value):
    print("Result is \(value)")
case .failure(let error):
    print("Failed with error: \(error.localizedDescription)")
}


/* 결과값
Result is 5
Failed with error: 0으로 나눌 수 없어요!
*/

비동기 작업이나 에러가 발생할 수 있는 작업의 결과를 명확하게 처리하기 위해 사용되는 열거형(enum)

  • 작업이 성공했을 때와 실패했을 때의 결과를 한번에 처리할 수 있도록 설계되어, 코드의 가독성을 높이고 에러처리를 직관적이게 할 수 있음
  • success, failure 두 가지로 정의
  • Success, Failure는 제네릭으로 되어있어 동적으로 사용 가능하며,
    Failure는 Error 프로토콜을 따르는 타입만 사용 가능
import Foundation

func divide(_ numerator: Int, by denominator: Int) -> Result<Int, Error> {
    guard denominator != 0 else {
        return .failure(NSError(domain: "나누기오류", code: 1, userInfo: [NSLocalizedDescriptionKey: "0으로 나눌 수 없어요!"]))
    }
    return .success(numerator / denominator)
}

let result = divide(10, by: 2)

switch result {
case .success(let value):
    print("Result is \(value)")
case .failure(let error):
    print("Failed with error: \(error.localizedDescription)")
}


let errorResult = divide(5, by: 0)
switch errorResult {
case .success(let value):
    print("Result is \(value)")
case .failure(let error):
    print("Failed with error: \(error.localizedDescription)")
}


/* 결과값
Result is 5
Failed with error: 0으로 나눌 수 없어요!
*/

0개의 댓글