Прежде всего, я не думаю, что необходимо складывать слои так, как вы делали, например, добавляя функциональность проверки в качестве слоя, с которым вы увеличиваете связь, создавая слой, зависящий от нижележащих слоев (разбор, сети и т.д.), вместо этого, почему бы не разделить проверки, чтобы сделать это только зависит от данных ?:
class ViewController: UIViewController {
var validator = InputValidator()
override func viewDidLoad() {
super.viewDidLoad()
do {
try validator.validateInput("INPUT")
try Fetcher.requestDataWithParams("INPUT")
}
catch {
handleError(error)
}
}
}
Теперь функциональность проверки не зависит от других слоев, поэтому связь будет течь, как это :
View Controller < ---> ParsingLayer < ---> NetworkingL ayer
Я переименовал слои, но они не обязательно должны быть такими, вы можете добавлять или удалять слои.
Я думаю, что это будет своего рода сложными, если я попытаюсь объяснить свой подход, поэтому я собираюсь привести пример с использованием предыдущих слоев, сначала нижний слой:
class NetworkingLayer {
class func requestData(params: AnyObject, completion: (getResult:() throw -> AnyObject) -> Void) -> Void {
session.dataTaskWithURL(url) { (data, urlResponse, var error) in
if let error = error {
completion(getResult: { throw error })
} else {
completion(getResult: { return data })
}
}
}
}
Я опустил некоторые разделы кода, но идея состоит в том, чтобы сделать любой необходимый шаг, чтобы заставить слой работать (создать сеанс и т. д.) и всегда поддерживать связь через завершение закрытия; слой сверху будет выглядеть следующим образом:
class ParsingLayer {
class func requestObject(params: AnyObject, completion: (getObject:() throw -> CustomObject) -> Void) -> Void {
NetworkingLayer.requestData(params, completion: { (getResult) -> Void in
do {
let data = try getResult()
let object = try self.parseData(data)
completion(getObject: { return object })
}
catch {
completion(getObject: { throw error })
}
})
}
}
Обратите внимание, что закрытие завершающего не то же самое, так как каждый слой добавляет функциональность, возвращаемый объект может меняться, также заметить, что код внутри do
заявления может потерпеть неудачу в двумя способами, сначала, если сетевой вызов завершается с ошибкой, а затем, если данные из сетевого уровня не могут быть проанализированы; снова соединение с верхним слоем всегда выполняется через завершение закрытия.
Наконец ViewController может вызвать следующий слой с помощью закрытия ожидаемого разборе слоя в этом случае и могут обрабатывать ошибки возникли в любом слое:
override func viewDidLoad() {
super.viewDidLoad()
do {
try validator.validateInput("INPUT")
try ParsingLayer.requestObject("INPUT", completion: { (getObject) in
do {
let object = try getObject()
try self.validator.validateOutput(object)
print(object)
}
catch {
self.handleError(error)
}
})
catch {
handleError(error)
}
}
Обратите внимание, что есть do catch
внутри это необходимо, так как вызов выполняется асинхронно, теперь, когда ответ прошел через все слои и фактически изменился на более специализированный тип, вы даже можете проверить результат без необходимости создания слоя для функциональность проверки.
Надеюсь, это поможет.
Спасибо за подробное объяснение. Мне понравился ваш подход к устранению более позднего для проверки. Но место, пусть data = try getResult() [В PARSING LAYER] & let object = try getObject() [In View Controller] не очень удобно. Лично я чувствую, что NSNotification чище и проще. Можете ли вы сказать, есть ли у вас какие-либо преимущества вашего подхода к уведомлениям? Потому что я не нахожу. Я был бы рад узнать об этом и отредактировать свой код соответствующим образом. – vivin
В этом случае уровень анализа зависит от сетевого уровня, связь имеет отношение 1 к 1, нет необходимости использовать систему вещания, некоторые из недостатков использования уведомлений: - не компилировать время для проверки на чтобы уведомления были правильно обработаны наблюдателями. -Не очень прослеживается (трудно отлаживать) - Добавляет еще один уровень сложности -Notification Names, а ключи словаря UserInfo должны быть известны как наблюдателям, так и контроллерам. Поскольку каждый может подписаться на уведомление, вероятно, существует плохая инкапсуляция данных – juanjo
Я должен был сказать, что я использовал подход в своем ответе в нескольких приложениях, у меня есть сетевой уровень, который обменивается данными с уровнем синтаксического анализа, который передает обратно на уровень репозитория, который наконец используется уровнем представления (View Controllers) и уровня обслуживания; сетевой уровень обрабатывает только связь с сервером, слой Parsing преобразует ответ JSON в объекты модели с помощью интроспекции и генериков, уровень репозитория обрабатывает URL-адреса и параметры, а все данные и ошибки протекают через цепочку без каких-либо проблем без уведомлений. – juanjo