APIClient.swift 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  1. //
  2. // APIClient.swift
  3. //
  4. import Foundation
  5. import Alamofire
  6. import ReactiveCocoa
  7. import ReactiveSwift
  8. /**
  9. 통신 구현 객체
  10. - Parameters:
  11. - url: String not Optinal 기본주소
  12. - reqParam: dictionary Optinal 전달 파라메터
  13. - headerParam: dictionary Optinal 헤더 파라메터
  14. - fileParam: dictionary Optinal 파일 파라메터
  15. - progressShow: Bool 프로그래스바의 표현여부
  16. - entype: ENCTYPE 인코딩타입, default 기본 json option
  17. - ENCTYPE: alamofire의 인코딩 타입을 감추는 래퍼
  18. - callBack: async 호출일 경우 외부 클로저와 브릿징해준다
  19. */
  20. class APIClient: NSObject {
  21. private var url:String!
  22. private var reqParam:[String:Any]?
  23. private var headerParam:[String:String]?
  24. private var fileParam:[[String:Data]]?
  25. private var progressShow:Bool = true
  26. private var entype:ENCTYPE = .default
  27. private var returnType:ENCTYPE = .json
  28. enum ENCTYPE{
  29. case `default`
  30. case json
  31. func getParameterEncoding() -> ParameterEncoding {
  32. switch self {
  33. case .default:
  34. return URLEncoding.default
  35. case .json:
  36. return JSONEncoding.default
  37. }
  38. }
  39. }
  40. private var method:METHOD = .post
  41. enum METHOD {
  42. case get
  43. case post
  44. func getHTTPMethod() -> HTTPMethod{
  45. switch self {
  46. case .get:
  47. return HTTPMethod.get
  48. case .post:
  49. return HTTPMethod.post
  50. }
  51. }
  52. }
  53. private var callBack = MutableProperty<Any?>(nil)
  54. /**
  55. 초기화
  56. - Parameters:
  57. - url: String not Optinal 기본주소
  58. - reqParam: dictionary Optinal 전달 파라메터
  59. - headerParam: dictionary Optinal 헤더 파라메터
  60. - fileParam: dictionary Optinal 파일 파라메터
  61. */
  62. init(_ url:String) {
  63. super.init()
  64. self.url = url
  65. }
  66. /**
  67. 파라메터설정
  68. - Parameters:
  69. - type: 딕셔너리
  70. - Returns: self
  71. */
  72. func param(reqParam:[String:Any]) -> APIClient {
  73. self.reqParam = reqParam
  74. return self
  75. }
  76. /**
  77. 파라메터설정
  78. - Parameters:
  79. - type: 딕셔너리
  80. - Returns: self
  81. */
  82. func param(fileParam:[[String:Data]]) -> APIClient {
  83. self.fileParam = fileParam
  84. return self
  85. }
  86. /**
  87. 파라메터설정
  88. - Parameters:
  89. - type: 딕셔너리
  90. - Returns: self
  91. */
  92. func param(headerParam:[String:String]) -> APIClient {
  93. self.headerParam = headerParam
  94. return self
  95. }
  96. /**
  97. 인코딩 타입설정
  98. - Parameters:
  99. - type: ENCTYPE
  100. - Returns: self
  101. */
  102. func enType(_ type:ENCTYPE) -> APIClient {
  103. self.entype = type
  104. return self
  105. }
  106. /**
  107. http 타입설정
  108. - Parameters:
  109. - type: METHOD
  110. - Returns: self
  111. */
  112. func meThod(_ method:METHOD) -> APIClient {
  113. self.method = method
  114. return self
  115. }
  116. /**
  117. 프로그래스바의 표현여부
  118. - Parameters:
  119. - isPro: Bool 표현여부
  120. - Returns: self
  121. */
  122. func isProgress(_ isPro:Bool) -> APIClient {
  123. self.progressShow = isPro
  124. return self
  125. }
  126. /**
  127. 파일 업로드를 위한 펑션
  128. - Parameters:
  129. - multipartFormData: closure로 들어오는 upload 객체
  130. */
  131. func upload(multipartFormData:MultipartFormData){
  132. guard let files = self.fileParam else{ return }
  133. for file in files{
  134. for (name, data) in file{
  135. multipartFormData.append(data, withName: name, fileName: "temp.jpg", mimeType: self.mimeTypeForData(data:data))
  136. }
  137. }
  138. guard let params = self.reqParam else{ return }
  139. for (key, val) in params{
  140. if let strigVal = val as? String{
  141. multipartFormData.append(strigVal.data(using: .utf8)!, withName: key)
  142. }else{
  143. multipartFormData.append(String(describing: val).data(using: .utf8)!, withName: key)
  144. }
  145. }
  146. }
  147. /**
  148. 콜백 리턴을 넣어주는 펑션
  149. - Parameters:
  150. - json: closure로 들어오는 DataResponse 객체
  151. */
  152. func responseJson(json:DataResponse<Any>){
  153. print(json.value)
  154. self.callBack.value = json.value as? [String:Any]
  155. }
  156. /**
  157. 콜백 리턴을 넣어주는 펑션
  158. - Parameters:
  159. - data: closure로 들어오는 DataResponse 객체
  160. */
  161. func responseData(data:DataResponse<Data>){
  162. self.callBack.value = data.value
  163. }
  164. /**
  165. 파일업로드 호출 펑션
  166. 직접 alamofire를 호출
  167. */
  168. func multiUpload(){
  169. Alamofire.upload(multipartFormData: self.upload,
  170. usingThreshold: UInt64(),
  171. to: self.url,
  172. method: self.method.getHTTPMethod(),
  173. headers: self.headerParam,
  174. encodingCompletion:{ encodingResult in
  175. switch encodingResult {
  176. case .success(let upload, _, _):
  177. switch self.returnType {
  178. case .default:
  179. upload.responseData(completionHandler: self.responseData)
  180. case .json:
  181. upload.responseJSON(completionHandler: self.responseJson)
  182. }
  183. case .failure(let encodingError):
  184. print("error:\(encodingError)")
  185. }
  186. })
  187. }
  188. /**
  189. 메인 비동기 호출 펑션
  190. fileParam이 있을경우 self.multiUpload()로 점프한다
  191. 그외 인코딩 타입에 따라 리스폰스 받은 객체를 completionHandle로 전송한다.
  192. - Parameters:
  193. - completionHandle: 클로저를 받아 비동기 호출후 값을 담아 전송
  194. */
  195. typealias CallBackHandler<T> = (T) -> Void
  196. public func connect<T>(completionHandle:@escaping CallBackHandler<T>){
  197. if T.self == [String:Any].self {
  198. self.returnType = .json
  199. }else{
  200. self.returnType = .default
  201. }
  202. self.callBack.signal.observe { (item) in
  203. guard let value = item.value as? T else{ return }
  204. completionHandle(value)
  205. }
  206. guard self.fileParam == nil else {
  207. self.multiUpload()
  208. return
  209. }
  210. let api = Alamofire.request(self.url, method: self.method.getHTTPMethod(), parameters: self.reqParam, encoding: self.entype.getParameterEncoding(), headers: self.headerParam)
  211. switch self.returnType {
  212. case .default:
  213. api.responseData(completionHandler: self.responseData)
  214. case .json:
  215. api.responseJSON(completionHandler: self.responseJson)
  216. }
  217. }
  218. /**
  219. 동기화 호출 펑션
  220. - Returns: DataResponse<Any> JSON OBJECT를 동기화 코드로 전송한다.
  221. */
  222. public func get<T>(type:T) -> DataResponse<T> {
  223. if T.self == [String:Any].self {
  224. self.returnType = .json
  225. }else{
  226. self.returnType = .default
  227. }
  228. let req = Alamofire.request(self.url, method: self.method.getHTTPMethod(), parameters: self.reqParam, encoding: self.entype.getParameterEncoding(), headers: self.headerParam)
  229. let semaphore = DispatchSemaphore(value: 0)
  230. var result: DataResponse<T>!
  231. var serializer: DataResponseSerializer<T>!
  232. switch self.returnType {
  233. case .default:
  234. serializer = DataRequest.dataResponseSerializer() as? DataResponseSerializer<T>
  235. case .json:
  236. serializer = DataRequest.jsonResponseSerializer() as? DataResponseSerializer<T>
  237. }
  238. req.response(queue: DispatchQueue.global(qos: .default), responseSerializer: serializer) { response in
  239. result = response as DataResponse<T>
  240. semaphore.signal()
  241. }
  242. _ = semaphore.wait(timeout: DispatchTime.distantFuture)
  243. return result
  244. }
  245. /**
  246. 파일 타입을 알아내는 펑션
  247. - Parameters:
  248. - data: Data file 객체
  249. - Returns: String mime 타일을 반납한다. ex) image/jpeg
  250. */
  251. public func mimeTypeForData(data:Data) -> String{
  252. var c = [UInt32](repeating: 0, count: 1)
  253. (data as NSData).getBytes(&c, length: 1)
  254. switch (c[0]) {
  255. case 0xFF:
  256. return "image/jpeg"
  257. case 0x89:
  258. return "image/png"
  259. case 0x47:
  260. return "image/gif"
  261. case 0x49:
  262. return "image/tiff"
  263. case 0x4D:
  264. return "image/tiff"
  265. case 0x25:
  266. return "application/pdf"
  267. case 0xD0:
  268. return "application/vnd"
  269. case 0x46:
  270. return "text/plain"
  271. default:
  272. return "application/octet-stream"
  273. }
  274. }
  275. }