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. self.callBack.value = json.value as? [String:Any]
  154. }
  155. /**
  156. 콜백 리턴을 넣어주는 펑션
  157. - Parameters:
  158. - data: closure로 들어오는 DataResponse 객체
  159. */
  160. func responseData(data:DataResponse<Data>){
  161. self.callBack.value = data.value
  162. }
  163. /**
  164. 파일업로드 호출 펑션
  165. 직접 alamofire를 호출
  166. */
  167. func multiUpload(){
  168. Alamofire.upload(multipartFormData: self.upload,
  169. usingThreshold: UInt64(),
  170. to: self.url,
  171. method: self.method.getHTTPMethod(),
  172. headers: self.headerParam,
  173. encodingCompletion:{ encodingResult in
  174. switch encodingResult {
  175. case .success(let upload, _, _):
  176. switch self.returnType {
  177. case .default:
  178. upload.responseData(completionHandler: self.responseData)
  179. case .json:
  180. upload.responseJSON(completionHandler: self.responseJson)
  181. }
  182. case .failure(let encodingError):
  183. print("error:\(encodingError)")
  184. }
  185. })
  186. }
  187. /**
  188. 메인 비동기 호출 펑션
  189. fileParam이 있을경우 self.multiUpload()로 점프한다
  190. 그외 인코딩 타입에 따라 리스폰스 받은 객체를 completionHandle로 전송한다.
  191. - Parameters:
  192. - completionHandle: 클로저를 받아 비동기 호출후 값을 담아 전송
  193. */
  194. typealias CallBackHandler<T> = (T) -> Void
  195. public func connect<T>(completionHandle:@escaping CallBackHandler<T>){
  196. if T.self == [String:Any].self {
  197. self.returnType = .json
  198. }else{
  199. self.returnType = .default
  200. }
  201. self.callBack.signal.observe { (item) in
  202. guard let value = item.value as? T else{ return }
  203. completionHandle(value)
  204. }
  205. guard self.fileParam == nil else {
  206. self.multiUpload()
  207. return
  208. }
  209. let api = Alamofire.request(self.url, method: self.method.getHTTPMethod(), parameters: self.reqParam, encoding: self.entype.getParameterEncoding(), headers: self.headerParam)
  210. switch self.returnType {
  211. case .default:
  212. api.responseData(completionHandler: self.responseData)
  213. case .json:
  214. api.responseJSON(completionHandler: self.responseJson)
  215. }
  216. }
  217. /**
  218. 동기화 호출 펑션
  219. - Returns: DataResponse<Any> JSON OBJECT를 동기화 코드로 전송한다.
  220. */
  221. public func get<T>(type:T) -> DataResponse<T> {
  222. if T.self == [String:Any].self {
  223. self.returnType = .json
  224. }else{
  225. self.returnType = .default
  226. }
  227. let req = Alamofire.request(self.url, method: self.method.getHTTPMethod(), parameters: self.reqParam, encoding: self.entype.getParameterEncoding(), headers: self.headerParam)
  228. let semaphore = DispatchSemaphore(value: 0)
  229. var result: DataResponse<T>!
  230. var serializer: DataResponseSerializer<T>!
  231. switch self.returnType {
  232. case .default:
  233. serializer = DataRequest.dataResponseSerializer() as? DataResponseSerializer<T>
  234. case .json:
  235. serializer = DataRequest.jsonResponseSerializer() as? DataResponseSerializer<T>
  236. }
  237. req.response(queue: DispatchQueue.global(qos: .default), responseSerializer: serializer) { response in
  238. result = response as DataResponse<T>
  239. semaphore.signal()
  240. }
  241. _ = semaphore.wait(timeout: DispatchTime.distantFuture)
  242. return result
  243. }
  244. /**
  245. 파일 타입을 알아내는 펑션
  246. - Parameters:
  247. - data: Data file 객체
  248. - Returns: String mime 타일을 반납한다. ex) image/jpeg
  249. */
  250. public func mimeTypeForData(data:Data) -> String{
  251. var c = [UInt32](repeating: 0, count: 1)
  252. (data as NSData).getBytes(&c, length: 1)
  253. switch (c[0]) {
  254. case 0xFF:
  255. return "image/jpeg"
  256. case 0x89:
  257. return "image/png"
  258. case 0x47:
  259. return "image/gif"
  260. case 0x49:
  261. return "image/tiff"
  262. case 0x4D:
  263. return "image/tiff"
  264. case 0x25:
  265. return "application/pdf"
  266. case 0xD0:
  267. return "application/vnd"
  268. case 0x46:
  269. return "text/plain"
  270. default:
  271. return "application/octet-stream"
  272. }
  273. }
  274. }