Skip to content

Latest commit

 

History

History
118 lines (92 loc) · 3.91 KB

9.Networking.md

File metadata and controls

118 lines (92 loc) · 3.91 KB

9. Networking

참고 문헌/웹

Q) 아래 예제들 모두 실행안되는데 뭐가 문제지...

A) 알아냈음.

참고: 모든 Cancelable은 저장해야한다. 그렇지 않으면 현재 코드 범위를 벗어날 때 deallocated 및 취소된다.

뭔 말이냐면 지금 Playground는 해당 코드를 함수에 넣어서 호출하고 있다. 함수가 종료되면서 모두 deallocated및 취소되고 있는 거임.

  1. Debugging 하면서 찾아낸거라 거기에 적혀있으니 거기를 보도록 하자.

URL세션 확장

Combine에서는 URLRequest과 URL만 가지고 네트워크 통신을 할 수 있는 2가지 api를 제공한다.

그 중 URL을 이용한 기본적인 예제

guard let url = URL(string: "<https://mysite.com/mydata.json>") else{return}

let subscription = URLSession.shared
    .dataTaskPublisher(for: url)
    .sink { completion in
        if case .failure(let err) = completion{
            print("Retrieving data failed with error \\(err)")
        }
    } receiveValue: { data, response in
        print("Retrieved data of size \\(data.count), response = \\(response)")
    }

Codable 지원

JsonDecoder, JsonEncoder를 이용해 response 받은 data를 디코딩할 수 있다.

guard let url = URL(string: "<https://mysite.com/mydata.json>") else{return}

let subscription = URLSession.shared
    .dataTaskPublisher(for: url)
    .tryMap{ data, _ in
        try JSONDecoder().decode(MyType.self, from: data)
    }
    .sink { completion in
        if case .failure(let err) = completion{
            print("Retrieving data failed with error \\(err)")
        }
    } receiveValue: { object in
        print("Retrieved object \\(object)")
    }

위의 예제에서는 tryMap을 사용했지만 코드를 줄이기 위해 다음과 같이 사용할 수도 있다.

let subscription = URLSession.shared
        .dataTaskPublisher(for: url)
        .map(\\.data)
        .decode(type: MyType.self, decoder: JSONDecoder())
        .sink { completion in
            if case .failure(let err) = completion{
                print("Retrieving data failed with error \\(err)")
            }
        } receiveValue: { object in
            print("Retrieved object \\(object)")
        }

여러 구독자에게 Network 데이터를 publish할 때

원래는 sink로 구독이 활성화되면 publisher가 작업을 바로 수행하게 됨.

그러면 API를 2번 실행하게 된다.

multicast를 사용하면 API를 한번만 실행할 수 있도록 만들어준다.

  • share랑 multicast 차이???
    • share 내부적으로는 PassThroughSubject를 autoconnect() 해주고 있음. 걍 share써라
let publisher = URLSession.shared
        .dataTaskPublisher(for: url)
        .map(\.data)
// multicast 내부 클로저에는 Subject가 들어가야함.
// 새로만들어도 되고 기존에 사용하던 subject가 들어가도 된다.
        .multicast{PassthroughSubject<Data, URLError>()}
    
// subscription하는데 ConnectablePublisher(multicast 반환 타입) 때문에 바로 작업을 시작할 수 없다.
let subscription1 = publisher
    .sink { completion in
        if case .failure(let err) = completion{
            print("Sink1 Retrieving data failed with error \(err)")
        }
    } receiveValue: { object in
        print("Sink1 Retrieved object \(object)")
    }
    .store(in: &cancelBag)

let subscription2 = publisher
    .sink { completion in
        if case .failure(let err) = completion{
            print("Sink2 Retrieving data failed with error \(err)")
        }
    } receiveValue: { object in
        print("Sink2 Retrieved object \(object)")
    }
    .store(in: &cancelBag)

// publisher를 connect한다.
// 작동을 시작하고 모든 구독자에게 publish한다.
let subscription = publisher.connect()