ios dev kangwook.

Swift) Semaphore 본문

Swift

Swift) Semaphore

kangwook 2022. 9. 25. 03:04

Semaphore는 쉽게 말하자면 비동기 구문을 동기화해주기 위한 객체라고 할 수 있다.

동기화가 되면 프로그램은 비동기 구문의 실행을 기다려주기 때문에, 비동기 구문을 사용하더라도 규칙적이고 정확한 프로그램의 개발이 가능하다.

  • 초기값을 0으로 가지는 semaphore 생성하는 구문
    • value 값은 음수가 되면 안됨
let semaphore = DispatchSemaphore(value: 0)
  • semaphore를 대기시키는 구문
semaphore.wait()
  • value 값을 +1 해주는 구문
    • 초기값이 0이었던 semaphore는 signal()함수를 통해 value = 1이 되므로 대기중에서 깨어나게 된다.
semaphore.signal()

예시

Semaphore를 이용한 비동기 구문의 동기화는 dataTask를 이용한 네트워크 통신에서 많이 쓰인다.

  • dataTask의 네트워크 통신은 비동기식이기 때문에 프로그램이 네트워킹하는 동안 기다려주지 않고 다른 프로그램 구문을 실행시켜버리기 때문

즉, 수신받은 네트워킹 결과에 따른 기능을 처리해줄 수 없다!

func ServerConnect(api: String, params: String) -> NSDictionary {
    let apiUrl = url + api
 
    var request = URLRequest(url: URL(string: apiUrl)!)
    request.httpMethod = "POST"
    request.httpBody = params.data(using: String.Encoding.utf8)
 
    var json: NSDictionary!
 
    let task = URLSession shared.dataTask(with request, completionHandler: { data, response, error in
        if error != nil {
            print("error : \(error)")
            return
        }
 
        print("Success Request, Params : \(params)")
        let responseString = String(data: data!, encoding: .utf8)
        print("responseString = \(responseString)")
        json = ParsingJSON(data: data!)
    })
    task.resume()
 
    print("resultJSON: \(json)"
    return json
}
  • task.resume()을 통해 네트워킹이 시작되지만, 비동기식이기 때문에 네트워킹이 끝나기도 전에 print("resultJSON: \(json)") 구문과 return json 구문이 실행된다.
  • 따라서 네트워킹이 끝나기도 전에 json이 사용되기 때문에 json의 값은 nil이 되어 오류가 발생하는 것!
func ServerConnect(api: String, params: String) -> NSDictionary {
    let apiUrl = url + api
 
    var request = URLRequest(url: URL(string: apiUrl)!)
    request.httpMethod = "POST"
    request.httpBody = params.data(using: String.Encoding.utf8)
 
    var json: NSDictionary!
    let semaphore = DispatchSemaphore(value: 0) // Semaphore선언
 
    let task URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in
        if error != nil {
            print("error : \(error)")
            return
        }
 
        print("Success Request, Params : \(params)")
 
        let responseString = String(data: data!, encoding: .utf8)
        print("responseString = \(responseString)")
 
        json = ParsingJSON(data: data!)
        semaphore.signal()  // Networking이 끝나면 신호 보내기
    })
    task.resume()
     
    semaphore.wait()        // Networking이 끝날 때 까지 대기
 
    print("resultJSON: \(json)")
    return json
}
  • 비동기식으로 작동하는 dataTask의 네트워킹이 완료될 때까지 기다리기 때문에 print되는 json값과 return되는 json값이 nil이 아닌 정확한 값이 전달되게 된다.

Sample 코드 작성

  • Network 버튼을 누르면 Server로부터 데이터를 받아와서 출력
  • semaphore를 사용함으로써 해당 네트워킹 작업이 끝날 때까지 기다리게 됨
// ...
func bindEvent() {
    // ...
    networkButton.rx.tap
        .withUnretained(self)
        .subscribe(onNext: { _ in
            let result = self.network()
            dump(result)
        }).disposed(by: disposeBag)
}
 
func network(params: String? = nil) -> Dictionary<String, Any> {
    let apiURL = "https://api.itbook.store/1.0/new"
    var request = URLRequest(url: URL(string: apiURL)!)
    request.httpMethod = "GET"
    var json: [String: Any]!
    let semaphore = DispatchSemaphore(value: 0)
    let task = URLSession.shared.dataTask(with: request, completionHandler: { data, response, error in
        if let error = error {
            print("error : \(error)")
        }
        let responseString = String(data: data!, encoding: .utf8)
        json = self.parsingJson(text: responseString!)
        semaphore.signal()
    })
    task.resume()
    semaphore.wait()
    print("ResultJSON: \(String(describing: json))")
    return json
}
// ...

 

참조

'Swift' 카테고리의 다른 글

Swift) Initialization  (0) 2022.10.02
Swift) Property  (0) 2022.09.25
Swift) DispatchQueue  (0) 2022.09.22
Swift) Concurrency, GCD  (0) 2022.09.20
Swift) Opaque Type  (0) 2022.09.11
Comments