https://www.youtube.com/watch?v=iHKBNYMWd5I

func downloadJson(_ url: String, _ completionHandler: @escaping (String?) -> Void) {
        DispatchQueue.global().async {
            let url = URL(string: MEMBER_LIST_URL)!
            let data = try! Data(contentsOf: url)
            let json = String(data: data, encoding: .utf8)
            
            DispatchQueue.main.async {
                completionHandler(json)
            }
        }
    }
    
    // MARK: SYNC
    
    @IBOutlet var activityIndicator: UIActivityIndicatorView!
    
    @IBAction func onLoad() {
        editView.text = ""
        setVisibleWithAnimation(activityIndicator, true)
        
        downloadJson(MEMBER_LIST_URL) { json in
            self.editView.text = json
            self.setVisibleWithAnimation(self.activityIndicator, false)
        }
    }

사람들이 생각한 것

@escaping 클로저를 안쓰고 String?을 리턴해줄수 없을까?

func downloadJson(_ url: String) -> **나중에생기는데이터<String?>** {
			return **나중에생기는데이터() { f in**
					DispatchQueue.global().async {
		          let url = URL(string: MEMBER_LIST_URL)!
		          let data = try! Data(contentsOf: url)
		          let json = String(data: data, encoding: .utf8)
		          
		          DispatchQueue.main.async {
		              f (json)
		          }
	        }
			**}**
       
    }
    
    // MARK: SYNC
    
    @IBOutlet var activityIndicator: UIActivityIndicatorView!
    
    @IBAction func onLoad() {
        editView.text = ""
        setVisibleWithAnimation(activityIndicator, true)
        
				let downloadedJsonData: 나중에생기는데이터<String?> = downloadJson(MEMBER_LIST_URL)
				
				 downloadedJsonData.나중에오면 { json in
            self.editView.text = json
            self.setVisibleWithAnimation(self.activityIndicator, false)
        }
    }
class 나중에생기는데이터<T> {
    private let task: (@escaping (T) -> Void) -> Void
    
    init(task: @escaping (@escaping (T) -> Void) -> Void) {
        self.task = task
    }
    
    func 나중에오면(_ f: @escaping (T) -> Void) {
        task(f)
    }
}

PromiseKit & Bolt

func downloadJson(_ url: String) -> **나중에생기는데이터<String?>** {
			return **나중에생기는데이터() { f in**
					DispatchQueue.global().async {
		          let url = URL(string: MEMBER_LIST_URL)!
		          let data = try! Data(contentsOf: url)
		          let json = String(data: data, encoding: .utf8)
		          
		          DispatchQueue.main.async {
		              f (json)
		          }
	        }
			**}**
       
    }
    
    // MARK: SYNC
    
    @IBOutlet var activityIndicator: UIActivityIndicatorView!
    
    @IBAction func onLoad() {
        editView.text = ""
        setVisibleWithAnimation(activityIndicator, true)
        
				let downloadedJsonData = downloadJson(MEMBER_LIST_URL)
				
				 downloadedJsonData
							.then { json in
			          self.editView.text = json
			          self.setVisibleWithAnimation(self.activityIndicator, false)
			        }
    }

Rxswift

func downloadJson(_ url: String) -> **나중에생기는데이터<String?>** {
			return **나중에생기는데이터() { f in**
					DispatchQueue.global().async {
		          let url = URL(string: MEMBER_LIST_URL)!
		          let data = try! Data(contentsOf: url)
		          let json = String(data: data, encoding: .utf8)
		          
		          DispatchQueue.main.async {
		              f (json)
		          }
	        }
			**}**
       
    }
    
    // MARK: SYNC
    
    @IBOutlet var activityIndicator: UIActivityIndicatorView!
    
    @IBAction func onLoad() {
        editView.text = ""
        setVisibleWithAnimation(activityIndicator, true)
        
				let downloadedJsonData = downloadJson(MEMBER_LIST_URL)
				
				 downloadedJsonData
							.subscribe { json in
			          self.editView.text = json
			          self.setVisibleWithAnimation(self.activityIndicator, false)
			        }
    }

비동기로 생기는 데이터를 Observable로 감싸서 리턴하는 방법

func downloadJson(_ url: String) -> Observable<String?> {
        return Observable.create() { f in
            DispatchQueue.global().async {
                let url = URL(string: MEMBER_LIST_URL)!
                let data = try! Data(contentsOf: url)
                let json = String(data: data, encoding: .utf8)
                
                DispatchQueue.main.async {
                    f.onNext(json)
                }
            }
            
            return Disposables.create()
        }
    }

Observable로 오는 데이터를 받아서 처리하는 방법

 // MARK: SYNC
    
    @IBOutlet var activityIndicator: UIActivityIndicatorView!
    
    @IBAction func onLoad() {
        editView.text = ""
        setVisibleWithAnimation(activityIndicator, true)
        
        downloadJson(MEMBER_LIST_URL)
            .subscribe { event in
                switch event {
                case .next(let json):
                    self.editView.text = json
                    self.setVisibleWithAnimation(self.activityIndicator, false)
                case .completed:
                    break
                case .error:
                    break
                }
            }
    }