Skip to content

Latest commit

 

History

History
204 lines (166 loc) · 5.83 KB

3차 스터디.md

File metadata and controls

204 lines (166 loc) · 5.83 KB

3차 스터디


프로젝트 개선 및 리팩토링 사항


통신: Moya


struct BaseResponseModel<Decode: Decodable>: Decodable {
    let status: Int
    let data: Decode?
    let success: Bool
    let message: String?
}
  • 데이터 통신 분기처리를 위한 모델 생성
final class APIService {
static let shared = APIService()
private init() {}

private let provider = MoyaProvider<APITarget>()

func requestCityActivity(cityID: Int, completion: @escaping (Result<CityActivityResponseModel, Error>) -> Void) {
      provider.request(.cityActivity(cityID: cityID)) { result in
          switch result {
          case let .success(success):
              let responseData = success.data
              do {
                  let decoded = try JSONDecoder().decode(CityActivityResponseModel.self, from: responseData)
                  completion(.success(decoded))
              } catch {
                  completion(.failure(error))
              }
          case let .failure(error):
              completion(.failure(error))
          }
      }
  }
}
  • Activity Data 통신을 위한 APIService 메소드 정의
typealias CityActivityResponseModel = BaseResponseModel<[_CityActivityResponseModel]>
  • typealias를 이용한 제네릭 모델 별칭 지정, 코드 간소화 및 가독성 개선
@escaping (Result<CityActivityResponseModel, Error>)
  • Generic 부분 추가 설명 , 하나 이상의 타입 인자를 사용할 수 있으며, 꺽쇠 안에서 타입 인자 이름을 콤마로 분리하여 작성한다. (ex. <T, M>)
  • Result 의 원래 인자는 <Success, Failure>
public protocol TargetType {

    /// The target's base `URL`.
    var baseURL: URL { get }

    /// The path to be appended to `baseURL` to form the full `URL`.
    var path: String { get }

    /// The HTTP method used in the request.
    var method: Moya.Method { get }

    /// Provides stub data for use in testing.
    var sampleData: Data { get }

    /// The type of HTTP task to be performed.
    var task: Task { get }

    /// The type of validation to perform on the request. Default is `.none`.
    var validationType: ValidationType { get }

    /// The headers to be used in the request.
    var headers: [String: String]? { get }
}

public extension TargetType {

    /// The type of validation to perform on the request. Default is `.none`.
    var validationType: ValidationType {
        return .none
    }
}
  • Moya의 TargetType protocol 을 채택하고 준수하여 열거형으로 APITarget구현

    //
    
    import Moya
    
    enum APITarget: TargetType {
        case medianHotelRead(cityID: Int, subCategory: Int)
        case cityActivity(cityID: Int)
        case tripCreate(cityID: Int, body: TripCreateRequestModel)
        case medianFoodRead(cityID : Int)
        
        var baseURL: URL {
            return URL(string: "http://13.125.42.117:3000")!
        }
        
        var path: String {
            switch self {
            case let .medianHotelRead(cityID, subCategory):
                return "/median/\(cityID)/\(subCategory)/hoteliOS/"
            case let .cityActivity(cityID):
                return "/citys/\(cityID)/Activity"
            case let .tripCreate(cityID, _):
                return "/trips/\(cityID)"
            case let .medianFoodRead(cityID):
                return "/median/\(cityID)/food"
            }
        }
        
        var method: Method {
            switch self {
            case .medianHotelRead:
                return .get
            case .cityActivity:
                return .get
            case .tripCreate:
                return .post
            case .medianFoodRead:
                return .get
            }
            // case. sendA:
            // return .post
        }
        
        var sampleData: Data {
            return .init()
        }
        
        var task: Task {
            switch self {
            case .medianHotelRead:
                return .requestPlain     
            case .cityActivity:
                return .requestPlain
            case let .tripCreate(cityID, body):
                let encoded = try! JSONEncoder().encode(body)
                return .requestCompositeData(bodyData: encoded, urlParameters: ["CityId": cityID])
            case let .medianFoodRead(cityID):
                return .requestPlain
            }
        }
        
        var headers: [String : String]? {
            return ["Content-Type": "application/json"]
        }
    }
enum APITarget: TargetType {
case medianHotelRead(cityID: Int, subCategory: Int)
case cityActivity(cityID: Int)
case tripCreate(cityID: Int, body: TripCreateRequestModel)
case medianFoodRead(cityID : Int)


var path: String {
switch self {
case let .cityActivity(cityID):
    return "/citys/\(cityID)/Activity"
    }
  }
func requestCityActivity(cityID: Int, completion: @escaping (Result<CityActivityResponseModel, Error>) -> Void) {
       provider.request(.cityActivity(cityID: cityID))
  • provider.request부분에서 .cityActivity부분이 APItarget을 사용 하는부분
  • provider.request( APITarget.cityActivity(cityID: cityID)) 축약형으로 표현
    override func viewDidAppear(_ animated: Bool) {
        let cityID = 1
        APIService.shared.requestCityActivity(cityID: cityID) { [weak self] result in
            switch result {
            case let .success(success):
                guard let data = success.data else { return }
                self?.responseModel = data
            case let .failure(error):
                print(error.localizedDescription)
            }
        }
    }
  • viewDidAppear ViewLifeCycle에서 APIService의 분기별로 처리해 놓은 (싱클턴패턴) 정의 해놨던 request 함수호출
  • To do 이미지캐싱