Ответ
В канонической реализации MVP (Model-View-Presenter) для iOS сильную ссылку на Presenter держит View (ViewController). Presenter, в свою очередь, держит слабую (weak) ссылку на View для предотвращения цикла сильных ссылок (retain cycle).
Почему такая схема?
- View создает и управляет жизненным циклом Presenter. Без сильной ссылки Presenter будет немедленно деаллоцирован.
- Presenter ссылается на View для обновления UI. Слабая ссылка гарантирует, что если View (например, ViewController) будет уничтожен, Presenter не будет удерживать его в памяти.
Пример реализации на Swift:
// 1. Протокол View с ограничением `AnyObject` для weak-ссылки
protocol MainViewProtocol: AnyObject {
func updateData(with items: [String])
}
// 2. Presenter со слабой ссылкой на View
class MainPresenter {
weak var view: MainViewProtocol?
private let service: DataService
init(view: MainViewProtocol, service: DataService) {
self.view = view
self.service = service
}
func loadData() {
service.fetchItems { [weak self] items in
self?.view?.updateData(with: items)
}
}
}
// 3. ViewController (View) с сильной ссылкой на Presenter
class MainViewController: UIViewController, MainViewProtocol {
var presenter: MainPresenter! // Сильная ссылка
override func viewDidLoad() {
super.viewDidLoad()
let service = DataService()
// View создает и хранит Presenter
presenter = MainPresenter(view: self, service: service)
presenter.loadData()
}
func updateData(with items: [String]) {
// Обновление UI
}
}
Ключевой вывод: Жизненный цикл Presenter зависит от View, а не наоборот.
Ответ 18+ 🔞
О, слушай, а вот этот ваш MVP, блядь! Ну классика жанра, ёпта. Все его обсуждают, а половина нихуя не понимает, где там что держит и кто кого ебёт.
Так вот, смотри, чтобы не было цикла сильных ссылок, который тебе всю память сожрёт, как голодный таракан крошки, нужно сделать всё по феншую.
Кто кого держит?
- Вьюха (ViewController) — это, блядь, главный барин. Она создаёт презентера и держит его за жопу сильной ссылкой (
strong). Потому что если она его отпустит, он тут же нахуй деаллоцируется, как последний алкаш на утреннике. Ему же жить-то надо, пока вьюха жива! - Презентер — это уже такой хитрожопый управленец. Он, конечно, должен вьюху обновлять, но держит он её за слабую ручку (
weak). Почему? А представь, вьюху закрыли, на другой экран перешли, а этот упырь продолжает её держать сильной хваткой и не отпускает в память вечную. Кринж, да? Слабая ссылка — это как сказать: «Да, я про тебя помню, но если тебя система приберет, я не буду плакать и держать твой труп».
Код, чтоб ты понимал, о какой хуйне я:
// 1. Протокол для Вьюхи. `AnyObject` — это магическая хуйня, чтобы weak можно было сделать.
protocol MainViewProtocol: AnyObject {
func updateData(with items: [String])
}
// 2. Сам презентер, хитрая жопа.
class MainPresenter {
weak var view: MainViewProtocol? // СЛАБАЯ ссылка, Карл! Чтобы не держать покойника.
private let service: DataService
init(view: MainViewProtocol, service: DataService) {
self.view = view
self.service = service
}
func loadData() {
service.fetchItems { [weak self] items in // И тут weak self, чтобы самому не зациклиться.
self?.view?.updateData(with: items) // Аккуратно так, на всякий пожарный.
}
}
}
// 3. Вьюконтроллер, который всем заправляет.
class MainViewController: UIViewController, MainViewProtocol {
var presenter: MainPresenter! // ВОТ ОНА, СИЛЬНАЯ ссылка! Презентер жив, пока жив этот экран.
override func viewDidLoad() {
super.viewDidLoad()
let service = DataService()
// Вьюха рожает презентера и говорит: «Живи, сынок, я тебя прокормлю».
presenter = MainPresenter(view: self, service: service)
presenter.loadData()
}
func updateData(with items: [String]) {
// Ну тут уже твой UI обновляй, как знаешь.
}
}
И главный вывод, который ты должен вынести, как икону из горящей избы: Презентер — это приложение к вьюхе, а не наоборот. Живёт он ровно до тех пор, пока живёт экран. А пытаться сделать наоборот — это прямой путь в ад утечек памяти, ёпта. Всё, вопрос закрыт, иди работай.