Skip to content

Latest commit

 

History

History
77 lines (61 loc) · 8.94 KB

File metadata and controls

77 lines (61 loc) · 8.94 KB

Время жизни

Любой объект имеет время жизни. Для упрощения работы с объектами был создан ARC, но даже его наличие не покрывает все нужды. Бывают случаи, когда объект может понадобиться в любое время, но при этом большую часть времени он никому не нужен. В принципе такие объекты являются одним из паттернов программирования и называются "одиночки".

В библиотеке время жизни объявляется у компонентов с помощью метода lifetime, который принимает один из возможных вариантов перечисления: .single, .perRun(.weak/.strong), .perContainer(.weak/.strong), .objectGraph, .prototype

Одиночка (single)

Если объект в программе существует на протяжении всего жизненного цикла программы в единственном экземпляре, то такой объект называется "одиночка". На самом деле в случае с библиотекой объект существует с момента вызова метода initializeSingletonObjects() и до завершения программы. Чтобы зарегистрировать компонент, который будет иметь единственный экземпляр класса в программе, надо объявить его как .single:

container.register(Cat.init)
  .lifetime(.single)

Если метод initializeSingletonObjects() не будет вызван у контейнера, то любые .single компоненты, ведут себя также как и .perRun(.strong).

Захват объекта (weak/strong)

У двух видов времени жизни появилась возможность указывать захватывать объект или нет. .weak - объект существует в единственном экземпляре в пределах указанной области видимости, то есть в зависимости от времени жизни. Но библиотека не держит этот объект в себе - то есть если приложение потеряет все ссылки на этот объект то он будет уничтожен, и при последующем обращении создан заново.
.strong - объект также существует в единственном экземпляре в пределах указанной области видимости, то есть в зависимости от времени жизни. Но библиотека держит этот объект в себе - то есть даже если приложение потярет все ссылки на этот объект, то при последующем обращении будет выдан тотже самый экземпляр класса.

Один на запуск (perRun)

Если объект в программе может существовать только в единственном экземпляре, и при этом создается при первом обращении, то такой объект называется "один на запуск". Чтобы зарегистрировать компонент, который будет иметь единственный экземпляр класса в программе, но при этом он будет создан при первом обращении, надо объявить его как .perRun(.weak/.strong):

container.register(Cat.init)
  .lifetime(.perRun(.single))

Один на контейнер (perContainer)

Если объект в программе может существовать в единственном экземпляре на протяжении жизненного цикла контейнера, то такой объект называется "один на контейнер". В случае если в программе есть всего один контейнер, то использование этого времени жизнии более предпочтительнее чем perRun. Чтобы зарегистрировать компонент, который будет иметь единственный экземпляр класса в программе, но при этом он будет создан при первом обращении, надо объявить его как .perRun(.weak/.strong):

builder.register(Cat.init)
  .lifetime(.perContainer(.strong))

Все объекты со временем жизни perContainer могут быть уничтожены функцией clean у контейнера. Это не гарантирует их физического уничтожения, но это гарантирует, что библиотека потеряет все ссылки на такие объекты.

Единственный в графе (objectGraph)

Объект создается каждый раз новый, но в рамках одного вызова функции resolve. То есть, если при создании какого либо объекта, этот объект нужен будет более чем один раз, то это будет один и тот же экземпляр класса. Основное предназначение для чего нужен этот вид времени жизни - циклические зависимости. В случае циклических зависимостей, объект с которого началось создание, будет присутствовать как миниум два раза: в начале и когда дойдет цикл. Из чего следуют, что при создании цикла хотя бы один класс должен иметь время жизни или .objectGraph или любой синглетон. Если быть точнее то этот "хотябы один класс" должен быть тот класс, с которого происходит создание объекта. Не стоит начинать создавать объекты с .prototype, несмотря на то, что это явно не запрещено и отработает, но скорей всего не так как хотелось бы.

builder.register(Cat.init)
  .lifetime(.objectGraph)

Всегда новый (prototype)

Самое простое в понимании время жизни - каждый раз при запросе у контейнера объекта, создается новый экземпляр. Во время разрешения зависимостей, будет создаваться новый экземпляр этого объекта, каждый раз, когда он будет запрошен. Объявляется он аналогичным образом:

builder.register(Cat.init)
  .lifetime(.prototype)

Пользовательский (custom)

В случае если хочется самому отвечать за время жизни некоторых объектов, можно использовать пользовательское время жизни. Для этого придется создать экземпляр класса DIScope:

let yourScope = DIScope(name: "your scope", storage: DICacheStorage())

И после при регистрации объекта во времени жизни указать его:

builder.register(Cat.init)
.lifetime(.custom(yourScope))

Хранилище можно создать свое собственное реализовав протокол DIStorage.

При создании scope можно указать политику хранения данных weak или strong:

DIScope(name: "your scope", storage: DICacheStorage(), policy: .weak)

Смысл политики такой же как и для .perRun или .perContainer.

По умолчанию (default)

Если у компоненты не указано время жизни, то используется prototype.