Swift 5: Что такое «Выходящее закрытие» фиксирует изменяющийся параметр «self» и как это исправить - PullRequest
2 голосов
/ 10 октября 2019

Здравствуйте, ребята, я пытаюсь создать простой и многократно используемый Swift Network Layer

Возможно, это не лучший способ зацикливания возвращаемых данных в поле зрения, но после того, как я попытался вернуть возвращенные данные API в Loopэто в представлении SwiftUI я получаю ошибку:

Escaping closure captures mutating 'self' parameter

И не знаю, где или что я пропустил в этом уроке

, и вот изображение файла

enter image description here

ContentView.swift

struct ContentView: View {

    var emptyDataArr: [CollectionItem] = []

    init() {
        ServiceLayer.request(router: Router.getSources) { (result: Result<[String : [CollectionItem]], Error>) in
            switch result {
            case .success(let data):
                print(data)
                self.emptyDataArr = data["custom_collections"]!

            case .failure:
                print(result)
            }
        }
    }

    var body: some View {
        VStack (alignment: .leading) {
            Text("No thing yet")
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Класс ServiceLayer ServiceLayer.swift

class ServiceLayer {
    // 1.
    class func request<T: Codable>(router: Router, completion: @escaping (Result<[String: [T]], Error>) -> ()) {
        // 2.
        var components = URLComponents()
        components.scheme = router.scheme
        components.host = router.host
        components.path = router.path
        components.queryItems = router.parameters
        // 3.
        guard let url = components.url else { return }
        var urlRequest = URLRequest(url: url)
        urlRequest.httpMethod = router.method
        // 4.
        let session = URLSession(configuration: .default)
        let dataTask = session.dataTask(with: urlRequest) { data, response, error in
            // 5.
            guard error == nil else {
                completion(.failure(error!))
                print(error?.localizedDescription)
                return
            }
            guard response != nil else {
                return
            }
            guard let data = data else {
                return
            }
            print(data)
            // 6.
            let responseObject = try! JSONDecoder().decode([String: [T]].self, from: data)
            // 7.
            DispatchQueue.main.async {
                // 8.
                completion(.success(responseObject))
            }
        }
        dataTask.resume()
    }
}

1 Ответ

3 голосов
/ 10 октября 2019

Проблема в том, что ContentView является структурой, что означает, что это тип значения. Вы не можете передать это закрытию и изменить его. Если бы вы это сделали, ничего бы не изменилось, потому что у замыкания была бы своя независимая копия структуры.

Ваша проблема в том, что вы смешали свой View и вашу модель. Может быть много, много копий данного Представления (каждый раз, когда оно передается функции, создается копия). Вы не хотели бы, чтобы каждая из этих копий инициировала запрос. Вместо этого переместите эту логику запроса в объект Model и просто позвольте представлению наблюдать ее.

...