@escaping

루픽코드

/** 첫번째파라미터에는 method파라미터에는 post 방식, 세번째는 요청할 쿼리파라미터를 param 으로 넣음 
딕셔너리로 파라미터 형태로 전달을 하면 알아서 유알엘 뒤에 쿼리파라미터를 추가해준다.*/

AF.request(path, method: .post, parameters: params, 
encoding: JSONEncoding(options: []), headers: headers).responseJSON { 
(response:AFDataResponse<Any>) in
public func login(_ path:String, params:[String : Any], completion: @escaping (_ result: JSON) -> Void) {
        
        if !Reachability.isConnectedToNetwork() {
            completion(JSON(["return":false, "code":"NET_MSG_0000"]))
            return
        }
        
        let headers:HTTPHeaders = ["Content-Type": "application/json",
                                   "Accept-Charset": "charset=UTF-8"]
        console.d(path, params)
        

/** 첫번째파라미터에는 method파라미터에는 post 방식, 세번째는 요청할 쿼리파라미터를 param 으로 넣음 
딕셔너리로 파라미터 형태로 전달을 하면 알아서 유알엘 뒤에 쿼리파라미터를 추가해준다.*/
/** 리퀘스트 메서드를 이용해 API를 호출하였으면 응답데이터를 받을 수 있는 메서드를 체이닝해줘야한다,
 .responseData(completionHandler:   */
        AF.request(path, method: .post, parameters: params, 
						encoding: JSONEncoding(options: []), headers: headers).responseJSON 
						{ (response:AFDataResponse<Any>) in
            
            #if DEBUG
            // debugPrint(response)
            #endif
            /** 요청에 대한 응답결과는 이렇게 적는다. 열거형으로 되어있어서 switch문으로 작성*/
            switch response.result {
            case .success(let data):
                
                if String(describing: data).contains("error") {
                    
                    #if DEBUG
                    print("An error has occurred.")
                    #endif
                    
                    var message = JSON(data)["message"].stringValue
                    if "" == message {
                        message = "service_error".localized()
                    }
                    
                    completion(JSON(["return":false, "code":"API_MSG_0000", "message":message]))
                    break
                }
                
                completion( JSON(data) )
                break
            case .failure(let error):
                
                #if DEBUG
                print(error)
                #endif
                completion(JSON(["return":false, "code":"API_MSG_0000", "message":"service_error".localized()]))
            }
        }
    }

패캠 코드

func fetchCovidOverView(
        completionHandler: @escaping Result<CityCovidOverView, Error>) -> Void
    ) {
        let url = "<http://www.bbbb.com>"
        let param = ["API키": "g33ighowgogiig"]
        
        AF.request(url, method: .get, parameter: param)
            .resoponseData(completionHandler: { response in
                switch response.result {
                case let .success(data):
                    do{
                        let decoder = JSONDecoder()
                        let result = try decoder.decode(CityCovidOverView.self, from: data)
                        completionHandler(.success(result))
                    } catch {
                        completionHandler(.failure(error))
                    }
                }
            case let .failure(error):
                complertionHandler(.failure(error))
            }
                           })
    }
    
    
    
}

<aside> 💡 @escaping 이라는 탈출 클로저를 사용하는 이유!

  1. 해당 클로저를 외부 변수/상수에 저장 가능합니다.
  2. 해당 함수가 끝나서 리턴된 이후에도 클로저 실행이 가능합니다. </aside>

예시

서버에서 이미지를 받아와서 UIImage형 변수에 저장하는 함수가 있다고 가정!

func setImage(url: String) -> UIImage {
	var result = UIImage()
	
	Alamofire.request(url).responseImage { (response) in
			if let image = response.result.value {
					result = image
				}	
		}
}

<aside> 💡 Alamofire 를 활용한 request는 동기적으로

var result = UIImage()가 끝나고 → Alamofire.request 가 끝나고 → return result 가 되는것이 아니라!

Alamofire.request는 비동기적으로 실행시켜놓고 Alamofire의 완료 여부와 상관없이 따로 return result가 실행된다.

즉, retrun result 가 실행되기 이전에 서버에서 이미지를 받아오는 부분이 안끝나면 빈 이미지가 return 되기때문에 서버에서 이미지를 받아오는 부분이 끝나고 정상적인 이미지가 넘어와야한다!

그래서 @escaping 클로저를 활용하게 된다.

</aside>

❌ 탈출클로저를 사용하지 않았을 경우

→ 함수가 리턴되기전에 서버 작업 완료되었는지 보장이 되지않는다.