관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - swift] Alamofire를 이용한 네트워크 연결 상태 감지 방법 (NetworkRechabilityManager) 본문

iOS 응용 (swift)

[iOS - swift] Alamofire를 이용한 네트워크 연결 상태 감지 방법 (NetworkRechabilityManager)

jake-kim 2023. 4. 8. 01:31

예제에 사용할 오픈소스

  • Alamofire (네트워크 연결 상태 감지)
  • RxSwift (Observable로 wrapping하여 사용하기 위해서 사용)

Network 상태 확인 방법

  • Alamofire에서 제공해주는 NetworkReachablilityManager 사용
    • 셀룰러 데이터에 연결 되었는지, 와이파이에 연결되어있는지 판단이 가능

https://alamofire.github.io/Alamofire/Classes/NetworkReachabilityManager.html

  • 내부 코드를 보면 SCNetworkReachabilityContext, SCNetworkReachabilitySetDispatchQueue 등 SCNetwork 관련 swift의 내장 api를 사용하여 판별

https://github.com/Alamofire/Alamofire/blob/master/Source/NetworkReachabilityManager.swift

  • SCNetwork를 wrapping해놓은 NetworkReachabilityManager를 사용하면 쉽게 네트워크 상태 확인이 가능
    • 내부적으로 NetworkStatusType을 정의하고 외부에서는 이 상태만 바라보게끔 NetworkStatus라는 것을 싱글톤으로 구현
    • 주의) statusObservable과 같은 프로퍼티에 .share() 오퍼레이터를 사용하는 경우가 있는데, Observable이 방출하고 있는 이벤트인 publish는 hot observable이라서 따로 share() 불필요 
    • share() 개념은 이전 포스팅 글 참고
import Alamofire
import RxSwift

enum NetworkStatusType {
    case disconnect
    case connect
    case unknown
}

final class NetworkStatus {
    static let shared = NetworkStatus()
    fileprivate let statusPublish = PublishSubject<NetworkStatusType>()
    var statusObservable: Observable<NetworkStatusType> {
        statusPublish
            .debug()
    }
    
    private init() {
        observeReachability()
    }
    
    private func observeReachability() {
        let reachability = NetworkReachabilityManager()
        reachability?.startListening(onUpdatePerforming: { [weak statusPublish] status in
            switch status {
            case .notReachable:
                statusPublish?.onNext(.disconnect)
            case
                .reachable(.ethernetOrWiFi),
                .reachable(.cellular)
            :
                statusPublish?.onNext(.connect)
            case .unknown :
                statusPublish?.onNext(.unknown)
            }
        })
    }
}
  • 사용하는쪽에서는 statusObservable을 구독하여 사용
NetworkStatus.shared.statusObservable
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)

rx 네임스페이스 넣기

  • 사용하는쪽에서 rx 네임스페이스로 isNetworkConnected라는 observable 프로퍼티에 접근하도록 수정
// before
NetworkStatus.shared.statusObservable
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)

// after
NetworkStatus.shared.rx.isNetworkConnected
    .subscribe(onNext: {
        print($0)
    })
    .disposed(by: disposeBag)
  • NetworkStatus에 NSObject를 따르도록 수정
    • NSObject가 없으면 extension Reactive를 해도 rx 네임스페이스 사용 불가
final class NetworkStatus: NSObject {
    ...
}
  • rx 네임스페이스 추가
    • extension Reactive로 읽기만 가능하도록 Observable<Bool> 타입으로 추가
// MARK: NetworkStatus+Rx
extension Reactive where Base: NetworkStatus {
    var isNetworkConnected: Observable<Bool> {
        let status = (try? base.behaviorPublish.value()) ?? .unknown
        guard case .connect = status else { return .just(false) }
        return .just(true)
    }
}

* 전체 코드: https://github.com/JK0369/ExNetworkCheck

* 참고:

https://developer.apple.com/documentation/systemconfiguration/1514911-scnetworkreachabilitysetdispatch?language=objc 

https://developer.apple.com/documentation/systemconfiguration/scnetworkreachabilitycontext

https://github.com/Alamofire/Alamofire/blob/master/Source/NetworkReachabilityManager.swift

https://alamofire.github.io/Alamofire/Classes/NetworkReachabilityManager.html

 

Comments