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
}
// ...
참조