//
// MySearchRouter.swift
// brandi
//
// Created by dev.geeyong on 2021/01/28.
//
import Foundation
import Alamofire
enum MySearchRouter: URLRequestConvertible {
case searchPhotos(term: String, pageNumber: String)
var baseURL: URL {
return URL(string: API.BASE_URL + "/search/")!
}
var method: HTTPMethod {
return .get
// switch self {
// case .searchPhotos:
// return .get
// }
}
var path: String {
switch self {
case .searchPhotos: return "image"
}
}
//let queryParam = ["query" : "코카콜라"]
var parameters: [String:String]{
switch self {
case let .searchPhotos(term,pageNumber): //검색어, 결과 페이지 번호, 1~50 사이의 값, 기본 값 1
return [
"query" : term,
"page" : pageNumber,
"size" : "30"
]
}
}
func asURLRequest() throws -> URLRequest {
let url = baseURL.appendingPathComponent(path)
print("asURLRequest- / image 처리 url: \(url)")
var request = URLRequest(url: url)
request.method = method
request = try URLEncodedFormParameterEncoder().encode(parameters, into: request)
// switch self {
// case let .get(parameters):
// request = try URLEncodedFormParameterEncoder().encode(parameters, into: request)
// case let .post(parameters):
// request = try JSONParameterEncoder().encode(parameters, into: request)
// }
return request
//https://dapi.kakao.com/v2/search/image?query=
}
}
MySearchRouter.swift 에서 Alamofire에 URLRequestConvertible을 상속받습니다. 그리고 API URL을 설정할 수 있고 method와 path, parameters까지 설정할 수 있습니다.
//
// MyLogger.swift
// brandi
//
// Created by dev.geeyong on 2021/01/28.
//
import Foundation
import Alamofire
final class MyLogger: EventMonitor{
let queue = DispatchQueue(label: "ApiLog")
func requestDidResume(_ request: Request) {
print("MyLogger - requestDidResume")
// debugPrint(request)
}
func request<Value>(_ request: DataRequest, didParseResponse response: DataResponse<Value, AFError>) {
print("MyLogger - didParseResponse")
// debugPrint(response)
}
}
MyLogger.swift에서는 EventMonitor을 상속받아 말 그대로 http통신 이벤트 모니터를 할 수 있습니다.
Swift에서 final키워드를 사용하면 메소드, 프로퍼티, 서브 스크립트가 오버라이드를 금지할 수 있습니다. 주로 재정의할 필요가 없을 때 final을 사용하는 것이 좋습니다. 클래스 자체가 상속되는 것을 막으려고 할 때에도 final을 사용할 수 있습니다
//
// Interceptor.swift
// brandi
//
// Created by dev.geeyong on 2021/01/28.
//
import Foundation
import Alamofire
class MyInterceptor: RequestInterceptor{
//카카오api key - accessToken
let accessToken: String = API.API_ID
func adapt(_ urlRequest: URLRequest, for session: Session, completion: @escaping (Result<URLRequest, Error>) -> Void){
print("Interceptor adapt")
var urlRequest = urlRequest
urlRequest.headers.add(.authorization(accessToken))
completion(.success(urlRequest))
//공통 파라매터 추가가능부분
//헤더에 카카오api key 추가
}
func retry(_ request: Request, for session: Session, dueTo error: Error, completion: @escaping (RetryResult) -> Void) { //결과 값이 없을 때 리트라이를 할거냐
print("Interceptor retry")
completion(.doNotRetry)
}
}
MyInterceptor.swift에서는 RequestInterceptor을 상속받습니다. 여기서 헤더를 추가합니다. 카카오 api에서는 api id값을 헤더에 추가시켜줍니다.
//
// AlamofireManager.swift
// brandi
//
// Created by dev.geeyong on 2021/01/28.
//
import Foundation
import Alamofire
import SwiftyJSON
final class AlamofireManager{
//싱글톤 적용
static let shared = AlamofireManager()
let interceptors = Interceptor(interceptors:
[
MyInterceptor() //headers 값 관리
])
let monitors = [MyLogger()]
var sesstion: Session
private init(){
sesstion = Session(interceptor: interceptors, eventMonitors: monitors)
}
func getPhotos(searcTerm userInput: String, pageNumber: String, completion: @escaping(Result<[Photo],MyError>)->Void){
print("Manager - getphotos")
self.sesstion
.request(MySearchRouter.searchPhotos(term: userInput, pageNumber: pageNumber))
.validate(statusCode: 200..<401)
.responseJSON(completionHandler: {response in
guard let reponseValue = response.value else { return }
let responseJson = JSON(reponseValue)
let jsonArray = responseJson["documents"]
var photos = [Photo]()
for (index, subJson): (String, JSON) in jsonArray{
//print("index: \(index) , subJson: \(subJson)")
let thumbnail = subJson["thumbnail_url"].string ?? ""
let datetime = subJson["datetime"].string ?? ""
let displaySite = subJson["display_sitename"].string ?? ""
let imageURL = subJson["image_url"].string ?? ""
let photoItem = Photo(thumbnailURL: thumbnail, datetime: datetime, displaySiteName: displaySite, imageURL: imageURL)
photos.append(photoItem)
}
//값 전송
if photos.count > 0{
completion(.success(photos))
}else{
completion(.failure(.noContent))
}
let jsonMetaData = responseJson["meta"]["is_end"]
if jsonMetaData == true{ //"is_end" 현재 페이지가 마지막 페이지인지 여부
return
}
})
}
}
AlamofireManager.swift에서는 위에 모든 swift 파일들을 모아 컨트롤을 해줍니다. 싱글톤을 적용을 해서 생성된 객체를 어디에서든지 참조할 수 있도록 했습니다. 인터셉터와 모니터를 만든 파일로 설정을 해주고, 세션을 통해 init을 해줍니다. 그리고 getPhotos라는 함수를 만들어 http통신을 해줍니다.
//MARK: - AlamofireManager - getDataResult
extension ViewController{
func getDataResult (searcTerm: String, pageNumber: Int) {
logoImageView.isHidden = true
AlamofireManager.shared.getPhotos(searcTerm: searcTerm, pageNumber: "\(pageNumber)" ,completion: {
[weak self]
result in
guard let self = self else {return}
switch result{
case .success(let fetchdPhotos):
print("success AlamofireManager", fetchdPhotos.count)
self.photosData = fetchdPhotos //데이터 저장
if fetchdPhotos.count > 30 { //최초 30개 데이터 fetch
print("30 data append")
for i in self.limit-30..<self.limit{
self.photos.append(self.photosData[i])
}
}else{ // 검색 결과의 이미지 갯수가 30개 이하인 경우 처리
for i in 0..<fetchdPhotos.count{
self.photos.append(self.photosData[i])
}
}
DispatchQueue.main.async {
self.collectionView.reloadData()
if self.limit == 30{ //새로운 이미지 검색시 스크롤을 맨 위로
let indexPath = IndexPath(item: 0, section: 0)
self.collectionView.scrollToItem(at: indexPath, at: .bottom, animated: true)
}
}
case .failure(let failError):
print("home get error \(failError.rawValue)")
self.view.makeToast(failError.rawValue, duration: 3.0, position: .center) //Toast_Swift
self.collectionView.reloadData ()
self.logoImageView.isHidden = false
}
})
}
}
이제 ViewController에 돌아와 만든 AlamofireManager을 통해 싱글톤으로 접근해서 getphotos라는 함수를 사용하는 모습입니다.
github.com/dev-geeyong/brandi_submit-main
'개발 > 아이오에스' 카테고리의 다른 글
swift 프로젝트를 스토리보드 없이(only code) 개발 셋팅하기 Set Up Project without Storyboard (0) | 2021.03.03 |
---|---|
xcode 에러 “The Local repository is out of date”…i have no branch how to solve this (0) | 2021.02.23 |
ios swift] 앱 내에서 메일 보내기 기능 구현 (0) | 2021.01.19 |
swift IOS] 네비게이션 컨트롤러 뒤로가기 버튼 텍스트 변경하기 (0) | 2021.01.18 |
ios swift] 이전 뷰로 이동하기 (코드) (0) | 2021.01.18 |