Насколько я понимаю, TripsFeedViewModel работает на MainActor из-за наблюдаемости, поэтому этот класс в основном изолирован от актера, MainActor. Так что в некотором смысле это предотвращает гонку данных. Затем, когда мы используем tripService.getTrips(), основной поток передаст его фоновому потоку для ожидания в очереди/блокировке актера TripService. Как только поток разрешен в актере TripService, он инициализирует NetworkRequestService, который затем привязывается к этому актеру, как и его функции. Поэтому, когда мы вызываем sendRequest, который является методом NetworkRequestService, он будет выполняться на актере TripService, и поток будет ждать, пока не будет получен ответ, удерживая блокировку. Однако если мы помечаем его как неизолированный, его можно передать фоновому потоку для завершения, после чего поток сможет его подхватить и снова войти в очередь. поэтому мы должны пометить его как неизолированный, а NetworkRequestService как отправляемый, потому что его безопасно отправлять между потоками, поскольку нет изменяемых состояний. Затем, когда дело доходит до PrivateTripResponse, технически его всегда можно отправить, потому что это структура и копия создается вместо ссылок на нее. Поскольку PrivateTripResponse соответствует Codable, он работает на MainActor, поэтому пометка его как неизолированного позволяет ему декодироваться и на фоновом актере, и это безопасно, поскольку его можно отправлять. Таким образом, sendbale и неизолированный работают рука об руку, давая компилятору знать, что что-то потокобезопасно для отправки между потоками с гонками данных. Будет ли это объяснение отражать то, что происходит во всем этом процессе?
import Foundation
@Observable
class TripsFeedViewModel {
var trips: [Trip] = []
private let tripService: TripServiceProtocol
init(tripService: TripServiceProtocol) {
self.tripService = tripService
}
func getTrip() async -> Void {
do {
let trips = try await tripService.getTrips()
await MainActor.run {
self.trips = trips.compactMap {
Trip(
id: $0.id,
tripName: $0.tripName,
location: $0.location,
budget: $0.budget,
isFavorite: $0.isFavorite,
startDate: $0.startDate,
endDate: $0.endDate,
imageURLString: $0.imageURL
)
}
}
} catch {
print("There was an error get your trips: \(error.localizedDescription)")
}
}
}
import Foundation
actor TripService: TripServiceProtocol {
private let networkService: NetworkRequestService
private let keychainService: KeychainService
private var activeTask: Task?
init(networkService: NetworkRequestService, keychainService: KeychainService) {
self.networkService = networkService
self.keychainService = keychainService
}
func getTrips() async throws -> [TripPrivateResponse] {
if let existing = activeTask {
return try await existing.value
}
let task = Task {
guard let url = URL(string: "local host url") else {
throw APIError.invalidURL
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
if let token = keychainService.getToken() {
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
}
return try await networkService.sendRequest(request: request, responseType: [TripPrivateResponse].self)
}
activeTask = task
defer { activeTask = nil }
return try await task.value
}
}
struct TripPrivateResponse: nonisolated Codable, Sendable {
let id: Int
let tripName: String
let location: String
let budget: Int
let isFavorite: Bool
let startDateString: String
let endDateString: String
let imageURLString: String
enum CodingKeys: String, CodingKey {
case id
case tripName = "title"
case location
case budget
case isFavorite = "is_favorite"
case startDateString = "start_date"
case endDateString = "end_date"
case imageURLString = "cover_image_url"
}
}
final class NetworkRequestService: Sendable {
// MARK: Sends the request and returns the response from FastAPI
nonisolated func sendRequest(request: URLRequest, responseType: Output.Type) async throws -> Output {
do {
/// 1. this sends the data to FastAPI then waits for a response
let (data, response) = try await URLSession.shared.data(for: request)
print("FASTAPI RESPONSE: \(String(data: data, encoding: .utf8) ?? "No Data")")
/// 2. checks the response (convert it to HTTPURLResponse type) making sure it has a successful status code
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
throw APIError.invalidResponse
}
/// 3. decode it to the DTO (UserPrivateResponse)
return try JSONDecoder().decode(responseType, from: data)
} catch let error as URLError {
throw APIError.networkError(error)
} catch let error as DecodingError {
throw APIError.decoding(error)
}
}
}
В Swift я пытаюсь понять ход логики при использовании Sendable, неизолированных и актеров. ⇐ IOS
Программируем под IOS
1777848595
Anonymous
Насколько я понимаю, TripsFeedViewModel работает на MainActor из-за наблюдаемости, поэтому этот класс в основном изолирован от актера, MainActor. Так что в некотором смысле это предотвращает гонку данных. Затем, когда мы используем tripService.getTrips(), основной поток передаст его фоновому потоку для ожидания в очереди/блокировке актера TripService. Как только поток разрешен в актере TripService, он инициализирует NetworkRequestService, который затем привязывается к этому актеру, как и его функции. Поэтому, когда мы вызываем sendRequest, который является методом NetworkRequestService, он будет выполняться на актере TripService, и поток будет ждать, пока не будет получен ответ, удерживая блокировку. Однако если мы помечаем его как неизолированный, его можно передать фоновому потоку для завершения, после чего поток сможет его подхватить и снова войти в очередь. поэтому мы должны пометить его как неизолированный, а NetworkRequestService как отправляемый, потому что его безопасно отправлять между потоками, поскольку нет изменяемых состояний. Затем, когда дело доходит до PrivateTripResponse, технически его всегда можно отправить, потому что это структура и копия создается вместо ссылок на нее. Поскольку PrivateTripResponse соответствует Codable, он работает на MainActor, поэтому пометка его как неизолированного позволяет ему декодироваться и на фоновом актере, и это безопасно, поскольку его можно отправлять. Таким образом, sendbale и неизолированный работают рука об руку, давая компилятору знать, что что-то потокобезопасно для отправки между потоками с гонками данных. Будет ли это объяснение отражать то, что происходит во всем этом процессе?
import Foundation
@Observable
class TripsFeedViewModel {
var trips: [Trip] = []
private let tripService: TripServiceProtocol
init(tripService: TripServiceProtocol) {
self.tripService = tripService
}
func getTrip() async -> Void {
do {
let trips = try await tripService.getTrips()
await MainActor.run {
self.trips = trips.compactMap {
Trip(
id: $0.id,
tripName: $0.tripName,
location: $0.location,
budget: $0.budget,
isFavorite: $0.isFavorite,
startDate: $0.startDate,
endDate: $0.endDate,
imageURLString: $0.imageURL
)
}
}
} catch {
print("There was an error get your trips: \(error.localizedDescription)")
}
}
}
import Foundation
actor TripService: TripServiceProtocol {
private let networkService: NetworkRequestService
private let keychainService: KeychainService
private var activeTask: Task?
init(networkService: NetworkRequestService, keychainService: KeychainService) {
self.networkService = networkService
self.keychainService = keychainService
}
func getTrips() async throws -> [TripPrivateResponse] {
if let existing = activeTask {
return try await existing.value
}
let task = Task {
guard let url = URL(string: "local host url") else {
throw APIError.invalidURL
}
var request = URLRequest(url: url)
request.httpMethod = "GET"
if let token = keychainService.getToken() {
request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
}
return try await networkService.sendRequest(request: request, responseType: [TripPrivateResponse].self)
}
activeTask = task
defer { activeTask = nil }
return try await task.value
}
}
struct TripPrivateResponse: nonisolated Codable, Sendable {
let id: Int
let tripName: String
let location: String
let budget: Int
let isFavorite: Bool
let startDateString: String
let endDateString: String
let imageURLString: String
enum CodingKeys: String, CodingKey {
case id
case tripName = "title"
case location
case budget
case isFavorite = "is_favorite"
case startDateString = "start_date"
case endDateString = "end_date"
case imageURLString = "cover_image_url"
}
}
final class NetworkRequestService: Sendable {
// MARK: Sends the request and returns the response from FastAPI
nonisolated func sendRequest(request: URLRequest, responseType: Output.Type) async throws -> Output {
do {
/// 1. this sends the data to FastAPI then waits for a response
let (data, response) = try await URLSession.shared.data(for: request)
print("FASTAPI RESPONSE: \(String(data: data, encoding: .utf8) ?? "No Data")")
/// 2. checks the response (convert it to HTTPURLResponse type) making sure it has a successful status code
guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else {
throw APIError.invalidResponse
}
/// 3. decode it to the DTO (UserPrivateResponse)
return try JSONDecoder().decode(responseType, from: data)
} catch let error as URLError {
throw APIError.networkError(error)
} catch let error as DecodingError {
throw APIError.decoding(error)
}
}
}
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия