https://medium.com/@GetInRhythm/closures-vs-combine-vs-async-await-993eb1da4d44

개요

스위프트에는 클로저, 컴바인, 어싱크/어웨잇 3가지의 비동기 코드 작성 방식이 존재함. 클로저는 self-contained blocks(독립적으로 실행 가능한 블록코드) 를정의해 비동기 작업을 다루고, Combine은 이벤트 스트림이라는 개념을 이용한다. Async-await은 새롭게 등장한 비동기 코드 방식으로 가독성과 유지보수성이 높은 코드를 작성 할 수 있다고 함.

역사

비교

URLSession을 활용하는 비동기 코드 예제이다.

  1. Closure - 선언

    func queryByFood(
    	name:String, 
    	result: @escaping(MealsList?, FoodError?) -> ()
     ) {
    	let path = "<https://www.exampels.com/api/json/s=\\(name)>"
    	let request = URLRequest(url: URL(String: path)!)
    	URLSession.shared.dataTask(with: request) { data,response,error in 
    		if let data = data {
    			if let list = try? JSONDecoder().decode(MealList.self, from: data){
    				result(list,nil)
    			} else { result(nil,.decoding)
    		} else { result(nil, .unknown(error?.locallizedDescription))
    	}
    }
    
  2. Combine - 선언

    func queryByFood(name: String) -> AnyPublisher<MealList, FoodError> { 
    	let path = "<https://www.examples/com/api/json/s=\\(name)>"
    	let requets = URLRequest(url: URL(string:path)!) 
    	return URLSession.shared.dataTaskPublisher(for: request)
    						.map(\\.data)
    						.decode(type: MealList.self, decoder: JSONDecoder())
    						.mapError { FoodError.unknown($0.locallizedDescription }
    						.eraseToAnyPublisher()
    } 
    
  3. Async / Await - 선언

    func queryByFood(name:String) async throws -> MealList {
    	let path = "<https://www.examples/com/api/json/s=\\(name)>"
    	let request = URLRequest(url: URL(string:path)!)
    	let (data,_) = try await URLSession.shared.data(for:request)
    	return try JSONDecoder().decode(MealList.Self, from:data)
    }
    
  4. Closures - 호출부

    func load(food:String) {
    	queryByFood(name:food) { list, error in 
    		DispatchQeue.main.async { 
    		}
    	}
    }
    
  5. Combine - 호출부

    func load(food:String) { 
    	queryByName(name:food) 
    		.flatMap{ .....logic }
    		.recevie(on:DispatchQueue.main)
    		.sink { .....some logic }
    		.store(in: &cancellables)
    }
    
  6. Async/Await

    @MainActor 
    func load(food:String) {
    	Task { 
    		do {
    			restults = try await queryByFood(name:food)
    			'''''some logic '''''
    
    		} catch { self.error = error.localizedDescription }
    
    	}
    }