Почему объект делегата равен нулю? - PullRequest
1 голос
/ 16 февраля 2020

У меня небольшая странная проблема с шаблоном делегата, и я не мог заставить его работать так, как ожидал. Я предполагаю, что я что-то здесь упускаю, но я не мог понять это сам.

Вот как определяются мои классы,

class NetworkManager {

    weak var delegate: DownloaderProtocol?

    func downloadFile(downloadUrl: URL ) {
        downloadTask(with: downloadUrl).resume()
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        delegate?.downloadCompleted(task: task, error: error)
    }
}


class DownloadManager: DownloaderProtocol {

    var networkManager: NetworkManager

    init(networkManager: NetworkManager) {
        self.networkManager = networkManager
    }

    func downloadMatches(urls: [String]) {
        self.networkManager.delegate = self

        for(....) {
            self.networkManager.downloadFile(url: url)
        }
    }

    func downloadCompleted(task: URLSessionTask, error: Error) {
        // Implementation
    }
}



class Matches {

    var networkManager: NetworkManager
    init() {
        self.networkManager = NetworkManager()
    }

    func getMatchSchedules(urls: [String] , completionHandler: @escaping (Result<Data, Error>) -> Void) {
        return DownloadManager.downloadMatches(urls: [String])
    }
}

В чем проблема?

Когда вызывается метод urlSession - didCompleteWithError, я вижу, что объект делегата nil .

Что я пробовал?

  1. Если я удаляю слабую ссылку делегата, то есть от weak var delegate: DownloaderProtocol? до var delegate: DownloaderProtocol?, тогда объект делегата не равен nil. Это работает нормально.
  2. Я даже пытался установить делегаты в классе Matches, но делегат по-прежнему отображается как nil

Любая помощь или указание приветствуются.

Ответы [ 2 ]

0 голосов
/ 16 февраля 2020

Вы можете использовать обратный вызов вместо делегата. Это гораздо проще, чем делегировать.

typealias APIServiceSuccessCallback = ((Any?) -> ())

ViewController A:

//call from A -> B result fire if completionHandler fire in VC B
    addCompanyTargetsController.responseCreateBookingObj = { [unowned self] (returnObject) in
                    if let object = returnObject as? [String:Any] {
                        if object["success"] as? Bool == true {
                            self.loadTargetList()//success block
                        }
                    }
                }

ViewController B:

var responseCreateBookingObj : APIServiceSuccessCallback? //declaration

func completionHandler() { //from where you fire call this method
        guard let callBack = self.responseCreateBookingObj else{
            return
        }
        callBack( true as AnyObject)
    }
0 голосов
/ 16 февраля 2020

хорошо, я рекомендую этот подход, так как это не весь ваш код, который был опубликован в вопросе, а только соответствующий.

 class NetworkManager {

    weak var delegate: DownloaderProtocol?

    func downloadFile(downloadUrl: URL ) {
        downloadTask(with: downloadUrl).resume()
    }

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        delegate?.downloadCompleted(task: task, error: error)
    }
}


class DownloadManager: DownloaderProtocol {

    var networkManager: NetworkManager

    init(networkManager: NetworkManager) {
        self.networkManager = networkManager
        self.networkManager.delegate = self
    }

    func downloadMatches(urls: [String]) {


        for url in urls {
            guard let url = URL(string: url) else {return}
            self.networkManager.downloadFile(downloadUrl: url)
        }
    }

    func downloadCompleted(task: URLSessionTask, error: Error) {
        // Implementation
    }
}



class Matches {

    var downloadManager: DownloadManager//NetworkManager
    init() {
        //self.networkManager = NetworkManager()
        //self.networkManager.delegate = DownloadManager()
        let networkManager = NetworkManager()
        self.downloadManager = DownloadManager(networkManager: networkManager)
    }

    func getMatchSchedules(urls: [String] , completionHandler: @escaping (Result<Data, Error>) -> Void) {
        return downloadManager.downloadMatches(urls: ["asadsdad"])
    }
}

вам нужен менеджер загрузок в совпадениях, у которого есть сетевой менеджер при создании совпадений вы создаете сетевой менеджер и устанавливаете в init менеджера загрузки, чтобы у вас был установлен делегат.

...