SlideShare une entreprise Scribd logo
1  sur  66
Télécharger pour lire hors ligne
YapDatabase
Головко Михаил
YapDatabase
Problem?
Рамблер Гороскопы
YapDatabase
План
• Реляционные и нереляционные БД
• Хранение и работа с данными в YapDatabase
• Расширения YapDatabase
• YapDatabase + VIPER
YapDatabase
Реляционная БД
Реляционная база данных — это совокупность
взаимосвязанных таблиц, каждая из которых
содержит информацию об объектах определенного
типа.
Таблицы реляционной БД должны отвечать
требованиям нормализации отношений.
YapDatabase
Реляционная БД
Плюсы
• Нет дублирования информации
• Над таблицами можно производить различные
операции
• Данные в таблице имеют чётко определённую
структуру
• Целостность данных гарантируется БД
YapDatabase
Реляционная БД
Минусы
• Для получения объекта со всеми связями нужно
делать сложные запросы
• Нужно поддерживать базу в нормализованном
виде
YapDatabase
Реляционная БД
YapDatabase
Нереляционная БД
Хранилище типа ключ-значение.
Это совокупность доменов (коллекций), каждый из
которых содержит объект любого типа.
YapDatabase
Нереляционная БД
Плюсы
• Динамическая модель данных, которая заранее
может быть не определена
• В рамках одного домена (коллекции) данные
могут иметь различную структуру
• Несвязанность данных
YapDatabase
Нереляционная БД
Минусы
• Контроль целостности данных лежит на
приложении
• Избыточность данных
YapDatabase
Нереляционная БД
YapDatabase
YapDatabase
• Нереляционная база данных (key/value)
• Открытый исходный код
• мм
• Контрибъютит Google
YapDatabase
Организация данных
collection key object metadata
sound 34 blob blob
album elvis blob blob
album ac/dc blob blob
sound 15 blob blob
sound 16 blob blob
YapDatabase
Коллекции
Sound
Album
Artist
YapDatabase
Коллекции
Elvis AC/DC
YapDatabase
Коллекции
Список Опубликованный Черновой
YapDatabase
Object
• Любой объект
• Для сохранения объекта используется NSCoding
• Можно описать свои Serializer/Deserializer
YapDatabase
Metadata
• Сохранение любой информацию
• json из которого был получен объект
• timestamp создания
• Опциональное поле
YapDatabase
Connection
• Подключение к базе, через которое можно
работать с данными
• Аналог NSManagedObjectContext
• Одно соединение на запись
• Несколько на чтение для ui
YapDatabase
Connection
YapDatabase *database = [[YapDatabase alloc] initWithPath:path];
YapDatabaseConnection *connection = [database newConnection];
YapDatabase
Transaction
• Обеспечивают доступ к данным базы
• Чтения и Записи
• Синхронные и асинхронные
YapDatabase
Connection
read
Transaction
Connection Connection
read
read
read
read
read
read
read
read
t
i
m
e
YapDatabase
Connection
write 1
Transaction
Connection Connection
read
read
read
read
write 2
read
write 3
read
Write Queue
t
i
m
e
YapDatabase
write 1
Connection
write 1
Transaction
Connection Connection
read
read
read
read
write 2
read
write 3
read
Write Queue
t
i
m
e
YapDatabase
Connection
write 1
Transaction
Connection Connection
read
read
read
read
write 2
read
write 3
read
Write Queue
write 1
write 2
t
i
m
e
YapDatabase
Connection
write
Transaction
Connection Connection
read
read
read
read
write 2
read
write 3
read
Write Queue
write 1 write 1
write 2
t
i
m
e
write 3
YapDatabase
Connection
write
Transaction
Connection Connection
read
read
read
read
write 2
read
write 3
read
Write Queue
write 1 write 1
write 2
write 3
t
i
m
e
YapDatabase
Transaction
• Транзакции в соединении выполняются
последовательно
• Все транзакции записи синхронизируются одной
глобальной очередью
YapDatabase
Transaction
// Write
[connection readWriteWithBlock:
^(YapDatabaseReadWriteTransaction *transaction) {
[transaction setObject:@"Hello"
forKey:@“World"
inCollection:@"example1"];
}];
// Read
[connection readWithBlock:
^(YapDatabaseReadTransaction *transaction) {
NSLog(@"%@ World", [transaction objectForKey:@“World"
inCollection:@"example1"]);
}];
YapDatabase
Кэширование
• Используется соединениями
• В зависимости от политики, различный подход к
работе с объектами
• Можно изменять размер и сбрасывать во время
выполнения
YapDatabase
Политики кэширования
• YapDatabasePolicyContainment - объекты
всегда достаются из базы
• YapDatabasePolicyShare - между всеми
соединениями шарятся одни экземпляры
объектов
• YapDatabasePolicyCopy - между соединениями
объекты копируются
YapDatabase
YapDatabaseTransaction
YapDatabaseConnection
Cache
TransactionQueue
Структура
YapDatabase
Serializer/Deserializer
Extensions
WriteQueue
SQLite
Расширения
YapDatabase
View
• Похоже на NSFetchedResultsController
• Вычисляется на этапе записи в БД
• Данные группированы по коллекциям
• Данные отсортированы
• Данные отфильтрованы
• Может содержать различные объекты
• Ручное обновление данных немного сложнее, чем
NSFetchedResultsController
YapDatabase
View
@{
@"books" : @[
@{@"fiction",@"key24"},
@{@"fantasy",@"key7"},
@{@"mystery",@"key11"}
],
@"magazines" : @[
@{@"gossip",@"key60"},
@{@"science",@"key49"},
@{@"travel",@"key82"}
]
};
YapDatabase
View
YapDatabaseViewGrouping *grouping = [YapDatabaseViewGrouping withRowBlock:
^NSString *(YapDatabaseReadTransaction *transaction,
NSString *collection, NSString *key, id object, id metadata) {
if ([object isKindOfClass:[BNBook class]])
return @"books";
return nil;
};
YapDatabaseViewSorting *sorting = [YapDatabaseViewSorting withObjectBlock:
^(YapDatabaseReadTransaction *transaction, NSString *group,
NSString *collection1, NSString *key1, id obj1
NSString *collection2, NSString *key2, id obj2) {
return [obj1 compareBookByTitleThenAuthor:obj2];
};
YapDatabaseView *databaseView =
[[YapDatabaseView alloc] initWithGrouping:grouping
sorting:sorting];
YapDatabase
Mapping (View)
NSIndexPath
UITableView YapDatabaseView
section
row
group
index
YapDatabase
Mapping (View)
• Настраивать список групп, их порядок
• Можно реверсировать данные
• Динамические и статические секции
• Динамически и статически диапазон
• Зависимость ячеек от другой
YapDatabase
Mapping (View)
YapDatabaseViewMappings *mappings = [YapDatabaseViewMappings
mappingsWithGroups:@[@"bond movies", @"bond actors" ]
view:@“myView"];
[mappings setIsDynamicSection:YES forGroup:@"bond movies”];
[mappings setIsReversed:YES forGroup:@"bond actors"];
YapDatabase
Mapping (View)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)sender {
return [mappings numberOfSections];
}
- (NSInteger)tableView:(UITableView *)sender numberOfRowsInSection
(NSInteger)section {
return [mappings numberOfItemsInSection:section];
}
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
__block id object = nil;
[databaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction){
object = [[transaction ext:@"myView"] objectAtIndexPath:indexPath
withMappings:mappings];
}];
// configure and return cell...
}
YapDatabase
YapDatabaseTransaction
YapDatabaseConnection
Cache
TransactionQueue
Структура
YapDatabase
Serializer/Deserializer
Extensions
WriteQueue
SQLite
YapDatabase
YapDatabaseViewMappingsYapDatabaseTransactionYapDatabaseViewTransaction
YapDatabaseConnection
Cache
TransactionQueue
Структура
YapDatabase
Serializer/Deserializer
Extensions
WriteQueue
SQLite
YapDatabaseExtension
YapDatabaseViewConnection
YapDatabase
FilteredViews
• Позволяет фильтровать View
• Поддерживает все возможности View
• Динамическое изменение фильтра
• Иерархия FilteredView!!!
YapDatabase
FilteredViews
YapDatabaseViewFiltering *filtering =
[YapDatabaseViewFiltering withObjectBlock:
^BOOL (YapDatabaseReadTransaction *transaction,
NSString *group, NSString *collection,
NSString *key, id object) {
return [(PhoneCall *)object isMissed];
}];
YapDatabaseFilteredView *filteredView =
[[YapDatabaseFilteredView alloc] initWithParentViewName:@"view-object"
filtering:filtering
versionTag:@"0"];
YapDatabase
Relationships
Правила one-to-one
• DeleteSourceIfDestinationDeleted
• DeleteDestinationIfSourceDeleted
Правила one-to-many
• DeleteSourceIfAllDestinationsDeleted
• DeleteDestinationIfAllSourcesDeleted
YapDatabase
Relationships
Правила уведомлений
• NotifyIfSourceDeleted
• NotifyIfDestinationDeleted
YapDatabase
Relationships
@implementation Player
- (nullable NSArray<YapDatabaseRelationshipEdge *> *)yapDatabaseRelationshipEdges {
if (avatarID == nil) return nil;
YapDatabaseRelationshipEdge *edge = // (player) --> (avatar)
[YapDatabaseRelationshipEdge edgeWithName:@"avatar"
destinationKey:avatarID
collection:@"avatars"
nodeDeleteRules:YDB_DeleteDestinationIfSourceDeleted |
YDB_NotifyIfDestinationDeleted];
return @[ edge ];
}
- (nullable id)yapDatabaseRelationshipEdgeDeleted:(YapDatabaseRelationshipEdge *)edge
withReason:(YDB_NotifyReason)reason {
if ([edge.name isEqualToString:@“avatar"]) {
id copy = [self copy];
copy.avatarID = nil;
return copy;
}
return nil;
}
YapDatabase
CoreData + VIPER
Interactor Service
NSManagedObject
Context
Presenter
PONSO mapping
YapDatabase
CoreData + VIPER
Interactor Service
NSManagedObject
Context
Presenter
PONSO mapping
NSManagedObject
YapDatabase
CoreData + VIPER
Interactor Service
NSManagedObject
Context
Presenter
PONSO mapping
NSManagedObject
YapDatabase
CoreData + VIPER
Interactor Service
NSManagedObject
Context
Presenter
PONSO mapping
NSManagedObject
YapDatabase
CoreData + VIPER
Interactor Service
NSManagedObject
Context
Presenter
PONSO mapping
NSManagedObject
YapDatabase
CoreData + VIPER
Interactor Service
NSManagedObject
Context
Presenter
PONSO mapping
PONSO
YapDatabase
CoreData + VIPER
Interactor Service
NSManagedObject
Context
Presenter
PONSO mapping
PONSO
YapDatabase
CoreData + VIPER
Interactor Service
NSManagedObject
Context
Presenter
PONSO mapping
PONSO
YapDatabase
YapDatabase + VIPER
Interactor Service
YapDatabase
Connection
Presenter
YapDatabase
YapDatabase + VIPER
Interactor Service
YapDatabase
Connection
Presenter
PONSO
YapDatabase
YapDatabase + VIPER
Interactor Service
YapDatabase
Connection
Presenter
PONSO
YapDatabase
YapDatabase + VIPER
Interactor Service
YapDatabase
Connection
Presenter
PONSO
YapDatabase
YapDatabase + VIPER
Interactor Service
YapDatabase
Connection
Presenter
PONSO
YapDatabase
Итог
Плюсы
• Нет NSManagedObject
• Если мы запросили данные - они точно будут
• Можно оптимизировать работу с данными при
помощи кэширования
• Не нужна перегонка объектов из
NSManagedObject в PONSO
YapDatabase
Итог
Плюсы
• Объекты можно использовать в разных потоках
• View с разнотипными объектами
• Можно писать свои расширения !
YapDatabase
Итог
Минусы
• Ручная миграция
• Нет понимания работы с коллекциями
• Сложная работа с relation
• Все данные объекта выгружаются в памяти
• Если нужны связи из других коллекций, их нужно
доставать отдельно
Стоит попробовать в наших
проектах?
Да
Конец

Contenu connexe

En vedette

En vedette (15)

Rambler.iOS #7: Прием платежей по банковским картам в iOS приложении
Rambler.iOS #7: Прием платежей по банковским картам в iOS приложенииRambler.iOS #7: Прием платежей по банковским картам в iOS приложении
Rambler.iOS #7: Прием платежей по банковским картам в iOS приложении
 
RDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по Dip
 
Rambler.iOS #7: Интернет-эквайринг 101
Rambler.iOS #7: Интернет-эквайринг 101Rambler.iOS #7: Интернет-эквайринг 101
Rambler.iOS #7: Интернет-эквайринг 101
 
Rambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеровRambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеров
 
RDSDataSource: OCLint
RDSDataSource: OCLintRDSDataSource: OCLint
RDSDataSource: OCLint
 
RDSDataSource: Promises
RDSDataSource: PromisesRDSDataSource: Promises
RDSDataSource: Promises
 
RDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDKRDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDK
 
Rambler.iOS #5: Разбираем Massive View Controller
Rambler.iOS #5: Разбираем Massive View ControllerRambler.iOS #5: Разбираем Massive View Controller
Rambler.iOS #5: Разбираем Massive View Controller
 
Rambler.iOS #6: Не рычите на pbxproj
Rambler.iOS #6: Не рычите на pbxprojRambler.iOS #6: Не рычите на pbxproj
Rambler.iOS #6: Не рычите на pbxproj
 
RDSDataSource: App Thinning
RDSDataSource: App ThinningRDSDataSource: App Thinning
RDSDataSource: App Thinning
 
Rambler.iOS #7: Построение сложного табличного интерфейса
Rambler.iOS #7: Построение сложного табличного интерфейсаRambler.iOS #7: Построение сложного табличного интерфейса
Rambler.iOS #7: Построение сложного табличного интерфейса
 
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.КассыRambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
Rambler.iOS #4: Создание модульных приложений на примере Рамблер.Кассы
 
RDSDataSource: Чистые тесты на Swift
RDSDataSource: Чистые тесты на SwiftRDSDataSource: Чистые тесты на Swift
RDSDataSource: Чистые тесты на Swift
 
RDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperiencedRDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperienced
 
Rambler.iOS #5: VIPER и Swift
Rambler.iOS #5: VIPER и SwiftRambler.iOS #5: VIPER и Swift
Rambler.iOS #5: VIPER и Swift
 

Similaire à RDSDataSource: YapDatabase

паттерны проектирования источников данных
паттерны проектирования источников данныхпаттерны проектирования источников данных
паттерны проектирования источников данных
Vitaliy Trenkenshu
 
SSAS Multidimension и Tabular: что выбрать?
SSAS Multidimension и Tabular: что выбрать?SSAS Multidimension и Tabular: что выбрать?
SSAS Multidimension и Tabular: что выбрать?
Andrey Korshikov
 
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Yandex
 
Query perfomance tuning
Query perfomance tuningQuery perfomance tuning
Query perfomance tuning
collabock
 
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Magneta AI
 
тест база данных. основные функции
тест база данных. основные функциитест база данных. основные функции
тест база данных. основные функции
JIuc
 
Олег Бартунов (ГАИШ МГУ), Александр Коротков (Интаро-Софт)
Олег Бартунов (ГАИШ МГУ), Александр Коротков (Интаро-Софт)Олег Бартунов (ГАИШ МГУ), Александр Коротков (Интаро-Софт)
Олег Бартунов (ГАИШ МГУ), Александр Коротков (Интаро-Софт)
Ontico
 

Similaire à RDSDataSource: YapDatabase (20)

Паттерны проектирования источников данных
Паттерны проектирования источников данныхПаттерны проектирования источников данных
Паттерны проектирования источников данных
 
паттерны проектирования источников данных
паттерны проектирования источников данныхпаттерны проектирования источников данных
паттерны проектирования источников данных
 
Oracle NoSQL Database
Oracle NoSQL DatabaseOracle NoSQL Database
Oracle NoSQL Database
 
Реляционные базы данных
Реляционные базы данныхРеляционные базы данных
Реляционные базы данных
 
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
Механизмы мониторинга баз данных: взгляд изнутри / Дмитрий Еманов (Firebird P...
 
Scala, SBT & Play! for Rapid Application Development
Scala, SBT & Play! for Rapid Application DevelopmentScala, SBT & Play! for Rapid Application Development
Scala, SBT & Play! for Rapid Application Development
 
Анализируем данные с Clickhouse
Анализируем данные с  ClickhouseАнализируем данные с  Clickhouse
Анализируем данные с Clickhouse
 
SSAS Multidimension и Tabular: что выбрать?
SSAS Multidimension и Tabular: что выбрать?SSAS Multidimension и Tabular: что выбрать?
SSAS Multidimension и Tabular: что выбрать?
 
Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...
Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...
Industrial Programming Java - Lection Pack 03 - Relational Databases - Lavren...
 
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
Хранение данных в iPhone. (FMDB, SQL-Persistence, CoreData)
 
Витрины данных - загрузка данных, разработка процессов ETL
Витрины данных - загрузка данных, разработка процессов ETLВитрины данных - загрузка данных, разработка процессов ETL
Витрины данных - загрузка данных, разработка процессов ETL
 
Query perfomance tuning
Query perfomance tuningQuery perfomance tuning
Query perfomance tuning
 
Rambler.iOS #2: Введение в RestKit
Rambler.iOS #2: Введение в RestKitRambler.iOS #2: Введение в RestKit
Rambler.iOS #2: Введение в RestKit
 
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
Scala, Play Framework и SBT для быстрого прототипирования и разработки веб-пр...
 
Alasql.js - SQL база данных на JavaScript / Андрей Гершун (МАГ КОНСАЛТИНГ)
Alasql.js - SQL база данных на JavaScript / Андрей Гершун (МАГ КОНСАЛТИНГ)Alasql.js - SQL база данных на JavaScript / Андрей Гершун (МАГ КОНСАЛТИНГ)
Alasql.js - SQL база данных на JavaScript / Андрей Гершун (МАГ КОНСАЛТИНГ)
 
#PostgreSQLRussia в банке Тинькофф, доклад №1
#PostgreSQLRussia в банке Тинькофф, доклад №1#PostgreSQLRussia в банке Тинькофф, доклад №1
#PostgreSQLRussia в банке Тинькофф, доклад №1
 
тест база данных. основные функции
тест база данных. основные функциитест база данных. основные функции
тест база данных. основные функции
 
Лекция Android. БД SQLite, ContentProvider, Loader
Лекция Android. БД SQLite, ContentProvider, LoaderЛекция Android. БД SQLite, ContentProvider, Loader
Лекция Android. БД SQLite, ContentProvider, Loader
 
Олег Бартунов (ГАИШ МГУ), Александр Коротков (Интаро-Софт)
Олег Бартунов (ГАИШ МГУ), Александр Коротков (Интаро-Софт)Олег Бартунов (ГАИШ МГУ), Александр Коротков (Интаро-Софт)
Олег Бартунов (ГАИШ МГУ), Александр Коротков (Интаро-Софт)
 
Управление данными (sql)
Управление данными (sql)Управление данными (sql)
Управление данными (sql)
 

Plus de RAMBLER&Co

Plus de RAMBLER&Co (13)

RDSDataSource: Основы LLVM
RDSDataSource: Основы LLVMRDSDataSource: Основы LLVM
RDSDataSource: Основы LLVM
 
Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!
 
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
 
Rambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memoryRambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memory
 
RDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграммRDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграмм
 
Rambler.iOS #8: Чистые unit-тесты
Rambler.iOS #8: Чистые unit-тестыRambler.iOS #8: Чистые unit-тесты
Rambler.iOS #8: Чистые unit-тесты
 
Rambler.iOS #8: Сервис-ориентированная архитектура
Rambler.iOS #8: Сервис-ориентированная архитектураRambler.iOS #8: Сервис-ориентированная архитектура
Rambler.iOS #8: Сервис-ориентированная архитектура
 
Rambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCoreRambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCore
 
RDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOSRDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOS
 
RDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwiftRDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwift
 
Rambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуйRambler.iOS #6: App delegate - разделяй и властвуй
Rambler.iOS #6: App delegate - разделяй и властвуй
 
Rambler.iOS #6: Pagination Demystified
Rambler.iOS #6: Pagination DemystifiedRambler.iOS #6: Pagination Demystified
Rambler.iOS #6: Pagination Demystified
 
Rambler.iOS #5: TDD и VIPER
Rambler.iOS #5: TDD и VIPERRambler.iOS #5: TDD и VIPER
Rambler.iOS #5: TDD и VIPER
 

RDSDataSource: YapDatabase