-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#84] Concurrency를 사용하여 앱에서 사용하는 네트워크 공통 로직 구현 #85
Open
seungchan2
wants to merge
9
commits into
develop
Choose a base branch
from
feature/#84
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+622
−0
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
jane1choi
reviewed
Jan 10, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
테스트에 대한 언급을 pr에서 언급해줘서 테스트 관련해서 코멘트 달아보자면...
protocol URLSessionProtocol {
func data(for request: URLRequest) async throws -> (Data, URLResponse)
func bytes(for request: URLRequest) async throws -> (URLSession.AsyncBytes, URLResponse)
}
extension URLSession: URLSessionProtocol { }
class MockURLProtocol: URLProtocol {
typealias RequestHandler: ((URLRequest) throws -> (Data?, URLResponse?, Error?))?
static var requestHandler: RequestHandler?
override class func canInit(with request: URLRequest) -> Bool {
return true
}
override class func canonicalRequest(for request: URLRequest) -> URLRequest {
return request
}
override func startLoading() {
guard let handler = MockURLProtocol.requestHandler else {
fatalError("Request handler is not set.")
}
do {
let (data, response, error) = try handler(request)
if let response = response {
client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
}
if let data = data {
client?.urlProtocol(self, didLoad: data)
}
if let error = error {
client?.urlProtocol(self, didFailWithError: error)
} else {
client?.urlProtocolDidFinishLoading(self)
}
} catch {
client?.urlProtocol(self, didFailWithError: error)
}
}
override func stopLoading() {
// 요청 취소 시 ...
}
}
final class MockURLSession {
private let urlSession: URLSession = {
let configuration = URLSessionConfiguration.ephemeral
configuration.protocolClasses = [MockURLProtocol.self]
return URLSession(configuration: configuration)
}()
private let isFailRequest: Bool
private let successMockData: Data
private let successStatusCode = 200
private let failureStatusCode = 401
init(isFailRequest: Bool = false, successMockData: Data) {
self.isFailRequest = isFailRequest
self.successMockData = successMockData
}
func data(for url: URL) async throws -> (Data, URLResponse) {
let successResponse = HTTPURLResponse(
url: url,
statusCode: successStatusCode,
httpVersion: "2",
headerFields: nil
)
let failureResponse = HTTPURLResponse(
url: url,
statusCode: failureStatusCode,
httpVersion: "2",
headerFields: nil
)
let response = isFailRequest ? failureResponse : successResponse
let data = isFailRequest ? nil : successMockData
MockURLProtocol.requestHandler = { _ in
return (data, response, nil)
}
return try await urlSession.data(for: URLRequest(url: url))
}
}
이런식으로 네트워크 요청 성공, 실패 케이스 테스트를 위한 Mock 객체를 만들어두고
let mockData = """
{ "message": "Success" }
""".data(using: .utf8)!
let mockSession = MockURLSession(isFailRequest: false, successMockData: mockData)
let url = URL(string: "https://example.com")!
Task {
do {
let (data, response) = try await mockSession.data(for: url)
if let response = response as? HTTPURLResponse {
print("Status Code: \(response.statusCode)")
}
print("Data: \(String(data: data, encoding: .utf8) ?? "")")
} catch {
print("Error: \(error)")
}
}
위와 같이 테스트 할 수 있도록 해도 좋을 것 같습니당! (특히나 지금 서버가 닫혀 있기 때문에...ㅎ)
FogFog-iOS/FogFog-iOS/ModernNetwork/ModernURLRequestBuildable.swift
Outdated
Show resolved
Hide resolved
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
🔍 What is this PR?
📝 Changes
1. URLSession -> 프로토콜 기반 설계
NetworkSession
ResponseDecoding
ModernURLRequestBuildable
2. 여러 시나리오를 고려한 네트워크 메소드 설계
ModernNetworkService.swift
파일을 보면 Networking 프로토콜 안에 5개의 메소드가 있습니다.여러가지 네트워크 시나리오에 따라서 다음과 같이 나눴습니다.
기본 네트워크는
request
메소드를 사용하면 되고, 취소 가능한 네트워크 요청은 Concurrency가 GCD 코드보다 취소에 장점이 있어 사용자가 네트워크 통신 중, 이탈하는 경우 등 다양한 엣지 케이스를 고려하여 일단 ㅎㅎ.. 5가지를 만들어 뒀습니다!내부 코드는 온라인 / 오프라인에서 설명드릴게요!
3. 에러 상태 정립 필요
4. actor를 사용한 네트워크 구현
https://developer.apple.com/videos/play/wwdc2021/10133/
5. 사용법
📮 관련 이슈