SlideShare a Scribd company logo
1 of 74
Download to read offline
PAGINATION
DEMYSTIFIED
Egor Tolstoy @igrekde
DISCLAIMER
ВЫСТУПЛЕНИЕ ОСНОВАНО НА ЛИЧНОМ
СТРАДАНИЯХ ОПЫТЕ.
ДОКЛАД СОДЕРЖИТ ДЕТАЛЬНОЕ ОПИСАНИЕ
ОТВРАТИТЕЛЬНЫХ КОСТЫЛЕЙ
И ПОЭТОМУ НЕ РЕКОМЕНДУЕТСЯ К ПРОСМОТРУ
НИКОМУ.
Локальная фильтрация
Динамический размер страницы
Пересобирается раз в час
Выдача лежит на CDN
Все еще limit/offset
authorId = postId >> 32
Техники пагинации
Как подступиться
Загрузка вниз
Обновление ленты
limit/offset
httр://api.соm/entries?offset=100&limit=20
0
1
2
cache server
0
1
2
3
4
5
6
7
0
1
2
cache server
0
1
2
3
4
5
6
7
offset: 3
limit: 5
3
4
5
6
7
0
1
2
cache server
0
1
2
3
4
5
6
7
offset: 3
limit: 5
3
4
5
6
7
3
4
5
6
7
3
4
5
6
7
Номера страниц
httр://api.соm/entries?page_number=3
cache server
0
1
2
0
cache server
0
1
2
0
page: 1
1
cache server
0
1
2
0
page: 1
11
2
1
Позиции элементов не меняются
Условия
Курсоры
httр://api.соm/entries?since=752284800&limit=10
httр://api.соm/entries? max_id=228&limit=10
httр://api.соm/entries? after=MTAxNTE&limit=10
cache server
0
1
2
21:04-
21:02-
19:35-
19:18-
17:44-
16:02-
15:58-
15:49-
15:40-
3
4
5
6
7
8
0
1
2
19:35-
19:18-
17:44-
15:21- 9
cache server
0
1
2
21:04-
21:02-
19:35-
19:18-
17:44-
16:02-
15:58-
15:49-
15:40-
3
4
5
6
7
8
0
1
2
19:35-
19:18-
17:44-
since: 17:44
limit: 5
15:21- 9
3
4
5
6
7
16:02-
15:58-
15:49-
15:40-
15:21-
cache server
0
1
2
21:04-
21:02-
19:35-
19:18-
17:44-
16:02-
15:58-
15:49-
15:40-
3
4
5
6
7
8
0
1
2
19:35-
19:18-
17:44-
since: 17:44
limit: 5
15:21- 9
3
4
5
6
7
16:02-
15:58-
15:49-
15:40-
15:21-
16:02-
15:58-
15:49-
15:40-
5
6
7
8
15:21- 9
Уникальный параметр каждого элемента
Сортировка выдачи не меняется
Условия
Изменение количества
элементов
Актуальность
выдачи
Обновление
контента
• Лента статична
• Новые элементы
добавляются
сверху
• Любая часть
выдачи может быть
изменена
• Выдача всегда
актуальна
• Выдача может быть
переформирована
• Отображаемые
данные не
обновляются
• Отображаемые
данные могут быть
изменены
1. Количество элементов не
меняется
2. Выдача всегда актуальна
3. Данные могут быть
изменены
Афиша.Рестораны
1. Новые элементы
добавляются только сверху
2. Выдача всегда актуальна
3. Данные могут быть
изменены
Афиша
1. Количество элементов не
меняется
2. Выдача может быть
переформирована
3. Данные не могут быть
изменены
Рамблер.Новости
1. Любая часть выдачи может
быть изменена
2. Выдача всегда актуальна
3. Данные могут быть
изменены
Рамблер.Почта
тем временем в офисе бэкенда
Решения проблем
пагинации на
клиенте
item 0
item 1
item 2
item 3
item 4
item 5
item 6
item 7
item 8
item 9
Загрузка вниз
Случай 1:
Лента статична
1/5
item 0
item 1
item 2
item 3
item 4
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
Загрузка вниз
Случай 1:
Лента статична
2/5
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
Загрузка вниз
Случай 1:
Лента статична
3/5
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
offset: 5
limit: 5
Загрузка вниз
Случай 1:
Лента статична
4/5
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5 (cached)
item 6 (cached)
item 7 (cached)
item 8 (cached)
item 9 (cached)
offset: 0
limit: 5
offset: 5
limit: 5
Загрузка вниз
Случай 1:
Лента статична
5/5
paging.startIndex = cachedPosts.count;
paging.count = 5;
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
Загрузка вниз
Случай 2:
Добавились новые
элементы
1/5
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
item 0' (new)
item 2' (new)
Загрузка вниз
Случай 2:
Добавились новые
элементы
2/5
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
offset: 5
limit: 5
item 0' (new)
item 2' (new)
Загрузка вниз
Случай 2:
Добавились новые
элементы
3/5
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5 (cached)
item 6 (cached)
item 7 (cached)
item 8
item 9
offset: 0
limit: 5
offset: 5
limit: 5
item 0' (new)
item 2' (new)
Загрузка вниз
Случай 2:
Добавились новые
элементы
4/5
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5 (cached)
item 6 (cached)
item 7 (cached)
item 8
item 9
offset: 0
limit: 5
offset: 5
limit: 5
offset: 8 + 2
item 0' (new)
item 2' (new)
Загрузка вниз
Случай 2:
Добавились новые
элементы
5/5
paging.startIndex = cachedPosts.count
+ intersections;
paging.count = 5;
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
Загрузка вниз
Случай 3:
Удалены старые
элементы
1/7
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
item 10
item 11
Загрузка вниз
Случай 3:
Удалены старые
элементы
2/7
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
item 10
item 11
offset: 5
limit: 5
Загрузка вниз
Случай 3:
Удалены старые
элементы
3/7
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7 (cached)
item 8 (cached)
item 9 (cached)
offset: 0
limit: 5
item 10 (cached)
item 11 (cached)
offset: 5
limit: 5
Загрузка вниз
Случай 3:
Удалены старые
элементы
4/7
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
...
Загрузка вниз
Случай 3:
Удалены старые
элементы
5/7
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
offset: 0
limit: 5
...
offset: 4
limit: 5
Загрузка вниз
Случай 3:
Удалены старые
элементы
6/7
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5 (cached)
item 6 (cached)
item 7 (cached)
item 8 (cached)
item 9
offset: 0
limit: 5
...
offset: 4
limit: 5
Загрузка вниз
Случай 3:
Удалены старые
элементы
7/7
paging.startIndex = startIndex - 1;
paging.count = 5;
еще одна шутка про Facebook
item 0
item 1
item 2
item 3
item 4
item 5
item 6
item 7
item 8
item 9
Загрузка вниз
Случай 4:
Порядок выдачи
пересобирается
1/5
item 0
item 1
item 2
item 3
item 4
item 5
item 6
item 7
item 8
item 9
items:
0,1,2,3,4
Загрузка вниз
Случай 4:
Порядок выдачи
пересобирается
2/5
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5
item 6
item 7
item 8
item 9
items:
0,1,2,3,4
Загрузка вниз
Случай 4:
Порядок выдачи
пересобирается
3/5
item 6
item 1 (cached)
item 4 (cached)
item 5
item 8
item 9
item 2 (cached)
item 0 (cached)
item 7
item 3 (cached)
Загрузка вниз
Случай 4:
Порядок выдачи
пересобирается
4/5
item 6 (cached)
item 1 (cached)
item 4 (cached)
item 5 (cached)
item 8 (cached)
item 9 (cached)
item 2 (cached)
item 0 (cached)
item 7 (cached)
item 3 (cached)
items:
5,6,7,8,9
Загрузка вниз
Случай 4:
Порядок выдачи
пересобирается
5/5
NSRange pageRange =
NSMakeRange(startIndex, 5);
NSArray *postIds = [snapshot
subarrayWithRange:pageRange];
item 0 (new)
item 1 (new)
item 2 (new)
item 3 (new)
item 4 (new)
item 5 (new)
item 7 (cached)
item 8 (cached)
item 9 (cached)
item 6 (new)
Обновление
Случай 1:
Появилось много
новых элементов
1/3
item 7 (cached)
item 8 (cached)
item 9 (cached)
offset: 0
limit: 5
item 0 (new)
item 1 (new)
item 2 (new)
item 3 (new)
item 4 (new)
item 5 (new)
item 6 (new)
Обновление
Случай 1:
Появилось много
новых элементов
2/3
item 0 (cached)
item 1 (cached)
item 2 (cached)
item 3 (cached)
item 4 (cached)
item 5 (new)
item 7 (cached)
item 8 (cached)
item 9 (cached)
offset: 0
limit: 5
item 6 (new)
Обновление
Случай 1:
Появилось много
новых элементов
3/3
if (intersections == 0) {
[self dropCache];
}
item 0 (cached)
item 1 (cached)
item 3 (cached)
item 4 (cached)
item 6 (cached)
item 7 (cached)
item 8 (deleted)
item 9 (cached)
item 5 (new)
item 2 (new)
Обновление
Случай 2:
Свободно
изменяемая лента
1/1
for (ShortPost *post in diff) {
[self updateCacheWith:post];
}
for (ShortPost *post in snapshot) {
if (![cachedPosts containsObject:post]) {
[self downloadPost:post];
}
}
for (Post *post in cachedPosts) {
if (![snapshot containsObject:post]) {
[self deletePost:post];
}
}
item 6
item 1 (cached)
item 4 (cached)
item 5
item 8
item 9
item 2 (cached)
item 0 (cached)
item 7
item 3 (cached)
Обновление
Случай 3:
Порядок выдачи
пересобирается
1/1
NSString *lastModified = [self makeFeedHeadRequest];
if (![lastModified isEqual:cachedLastModified]) {
[self dropCache];
[self obtainPostSnapshot];
[self obtainFirstPage];
}
item 0 (cached)
item 1 (updated)
item 2 (cached)
item 3 (updated)
item 4 (updated)
item 5
item 6
item 7
item 8
item 9
Обновление
Случай 4:
Данные элементов
меняются
1/1
for (NSUInteger i = 0; i < cachedPosts.count; i++) {
Post *cachedPost = cachedPosts[i];
ShortPost *post = snapshot[i];
if (![cachedPost isEqual:post]) {
[cachedPost updatePostWithShortPost:post];
}
}
posts: NSArray <Post *>
snapshot: NSArray <NSString *>
offset: NSUInteger
maxCount: NSUInteger
lastModified: NSDate
Feed
PostService
loadPosts
didLoad
Cache
PostService
loadPosts
didLoad
Cache
CacheTracker
PostService
loadPosts
didLoad
Cache
PagingFacade
PostService
ViewController
FeedService CacheUpdater
SnapshotProcessor
PagingCalculator
@protocol PostPagingFacade <NSObject>
- (void)loadNextPageWithBlock:(ErrorBlock)block;
- (void)refreshCategoryWithBlock:(ErrorBlock)block;
- (void)reloadCategoryWithBlock:(ErrorBlock)block;
@end
Клиент должен быть
простым
Техники пагинации
Как подступиться
Загрузка вниз
Обновление ленты
Egor Tolstoy @igrekde
не смог придумать
заключительную фразу

More Related Content

What's hot

JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.Igor Shkulipa
 
JavaScript Базовый. Занятие 08.
JavaScript Базовый. Занятие 08.JavaScript Базовый. Занятие 08.
JavaScript Базовый. Занятие 08.Igor Shkulipa
 
View как чистая функция от состояния базы данных - Илья Беда, bro.agency
View как чистая функция от состояния базы данных  - Илья Беда, bro.agencyView как чистая функция от состояния базы данных  - Илья Беда, bro.agency
View как чистая функция от состояния базы данных - Илья Беда, bro.agencyit-people
 
Выжить с помощью ООП. Максим Гопей
Выжить с помощью ООП. Максим ГопейВыжить с помощью ООП. Максим Гопей
Выжить с помощью ООП. Максим ГопейEatDog
 
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...CodeFest
 
[JAM 1.1] Clean Code (Paul Malikov)
[JAM 1.1] Clean Code (Paul Malikov)[JAM 1.1] Clean Code (Paul Malikov)
[JAM 1.1] Clean Code (Paul Malikov)Evgeny Kaziak
 
Selenium, а давай подождем?
Selenium, а давай подождем?Selenium, а давай подождем?
Selenium, а давай подождем?SQALab
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеPython Meetup
 
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...Ontico
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокAndrey Karpov
 
Секвенциальный анализ
Секвенциальный анализСеквенциальный анализ
Секвенциальный анализIvan Ignatyev
 
Using perl6-pod
Using perl6-podUsing perl6-pod
Using perl6-podzagru
 
«Introduction to malware reverse engineering» by Sergey Kharyuk aka ximerus
 «Introduction to malware reverse engineering» by Sergey Kharyuk aka ximerus «Introduction to malware reverse engineering» by Sergey Kharyuk aka ximerus
«Introduction to malware reverse engineering» by Sergey Kharyuk aka ximerus0xdec0de
 
Доклад Сергея Аверина на CodeFest-2013. "MySQL+HandlerSocket=NoSQL".
Доклад Сергея Аверина на CodeFest-2013. "MySQL+HandlerSocket=NoSQL".Доклад Сергея Аверина на CodeFest-2013. "MySQL+HandlerSocket=NoSQL".
Доклад Сергея Аверина на CodeFest-2013. "MySQL+HandlerSocket=NoSQL".Badoo Development
 
Изоморфные приложения и Python - Виталий Глибин, Huntflow
Изоморфные приложения и Python - Виталий Глибин, HuntflowИзоморфные приложения и Python - Виталий Глибин, Huntflow
Изоморфные приложения и Python - Виталий Глибин, Huntflowit-people
 
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Sigma Software
 

What's hot (20)

JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.JavaScript Базовый. Занятие 07.
JavaScript Базовый. Занятие 07.
 
JavaScript Базовый. Занятие 08.
JavaScript Базовый. Занятие 08.JavaScript Базовый. Занятие 08.
JavaScript Базовый. Занятие 08.
 
View как чистая функция от состояния базы данных - Илья Беда, bro.agency
View как чистая функция от состояния базы данных  - Илья Беда, bro.agencyView как чистая функция от состояния базы данных  - Илья Беда, bro.agency
View как чистая функция от состояния базы данных - Илья Беда, bro.agency
 
Выжить с помощью ООП. Максим Гопей
Выжить с помощью ООП. Максим ГопейВыжить с помощью ООП. Максим Гопей
Выжить с помощью ООП. Максим Гопей
 
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
CodeFest 2011. Крестьянинов М. — Обзор аспектно-ориентированного программиров...
 
Survive with OOP
Survive with OOPSurvive with OOP
Survive with OOP
 
JRebel
JRebelJRebel
JRebel
 
[JAM 1.1] Clean Code (Paul Malikov)
[JAM 1.1] Clean Code (Paul Malikov)[JAM 1.1] Clean Code (Paul Malikov)
[JAM 1.1] Clean Code (Paul Malikov)
 
Selenium, а давай подождем?
Selenium, а давай подождем?Selenium, а давай подождем?
Selenium, а давай подождем?
 
Очередной скучный доклад про логгирование
Очередной скучный доклад про логгированиеОчередной скучный доклад про логгирование
Очередной скучный доклад про логгирование
 
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
То, что вы хотели знать о HandlerSocket, но не смогли нагуглить / Сергей Авер...
 
PVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибокPVS-Studio в 2021 - Примеры ошибок
PVS-Studio в 2021 - Примеры ошибок
 
Секвенциальный анализ
Секвенциальный анализСеквенциальный анализ
Секвенциальный анализ
 
Using perl6-pod
Using perl6-podUsing perl6-pod
Using perl6-pod
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Javascript
JavascriptJavascript
Javascript
 
«Introduction to malware reverse engineering» by Sergey Kharyuk aka ximerus
 «Introduction to malware reverse engineering» by Sergey Kharyuk aka ximerus «Introduction to malware reverse engineering» by Sergey Kharyuk aka ximerus
«Introduction to malware reverse engineering» by Sergey Kharyuk aka ximerus
 
Доклад Сергея Аверина на CodeFest-2013. "MySQL+HandlerSocket=NoSQL".
Доклад Сергея Аверина на CodeFest-2013. "MySQL+HandlerSocket=NoSQL".Доклад Сергея Аверина на CodeFest-2013. "MySQL+HandlerSocket=NoSQL".
Доклад Сергея Аверина на CodeFest-2013. "MySQL+HandlerSocket=NoSQL".
 
Изоморфные приложения и Python - Виталий Глибин, Huntflow
Изоморфные приложения и Python - Виталий Глибин, HuntflowИзоморфные приложения и Python - Виталий Глибин, Huntflow
Изоморфные приложения и Python - Виталий Глибин, Huntflow
 
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин Как навести порядок в коде вашего web-приложения, Андрей Чебукин
Как навести порядок в коде вашего web-приложения, Андрей Чебукин
 

More from RAMBLER&Co

RDSDataSource: Основы LLVM
RDSDataSource: Основы LLVMRDSDataSource: Основы LLVM
RDSDataSource: Основы LLVMRAMBLER&Co
 
Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!Rambler.iOS #9: Анализируй это!
Rambler.iOS #9: Анализируй это!RAMBLER&Co
 
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?
Rambler.iOS #9: Нужны ли бэкенд-разработчики, когда есть Swift?RAMBLER&Co
 
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 memoryRAMBLER&Co
 
RDSDataSource: Чистые тесты на Swift
RDSDataSource: Чистые тесты на SwiftRDSDataSource: Чистые тесты на Swift
RDSDataSource: Чистые тесты на SwiftRAMBLER&Co
 
RDSDataSource: OCLint
RDSDataSource: OCLintRDSDataSource: OCLint
RDSDataSource: OCLintRAMBLER&Co
 
RDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграммRDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграммRAMBLER&Co
 
RDSDataSource: App Thinning
RDSDataSource: App ThinningRDSDataSource: App Thinning
RDSDataSource: App ThinningRAMBLER&Co
 
RDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRAMBLER&Co
 
RDSDataSource: YapDatabase
RDSDataSource: YapDatabaseRDSDataSource: YapDatabase
RDSDataSource: YapDatabaseRAMBLER&Co
 
Rambler.iOS #8: Чистые unit-тесты
Rambler.iOS #8: Чистые unit-тестыRambler.iOS #8: Чистые unit-тесты
Rambler.iOS #8: Чистые unit-тестыRAMBLER&Co
 
Rambler.iOS #8: Сервис-ориентированная архитектура
Rambler.iOS #8: Сервис-ориентированная архитектураRambler.iOS #8: Сервис-ориентированная архитектура
Rambler.iOS #8: Сервис-ориентированная архитектураRAMBLER&Co
 
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 JavaScriptCoreRAMBLER&Co
 
Rambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеровRambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеровRAMBLER&Co
 
RDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperiencedRDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperiencedRAMBLER&Co
 
RDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDKRDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDKRAMBLER&Co
 
RDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOSRDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOSRAMBLER&Co
 
RDSDataSource: Promises
RDSDataSource: PromisesRDSDataSource: Promises
RDSDataSource: PromisesRAMBLER&Co
 
RDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwiftRDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwiftRAMBLER&Co
 
Rambler.iOS #7: Построение сложного табличного интерфейса
Rambler.iOS #7: Построение сложного табличного интерфейсаRambler.iOS #7: Построение сложного табличного интерфейса
Rambler.iOS #7: Построение сложного табличного интерфейсаRAMBLER&Co
 

More from RAMBLER&Co (20)

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: Чистые тесты на Swift
RDSDataSource: Чистые тесты на SwiftRDSDataSource: Чистые тесты на Swift
RDSDataSource: Чистые тесты на Swift
 
RDSDataSource: OCLint
RDSDataSource: OCLintRDSDataSource: OCLint
RDSDataSource: OCLint
 
RDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграммRDSDataSource: Построение UML диаграмм
RDSDataSource: Построение UML диаграмм
 
RDSDataSource: App Thinning
RDSDataSource: App ThinningRDSDataSource: App Thinning
RDSDataSource: App Thinning
 
RDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по DipRDSDataSource: Мастер-класс по Dip
RDSDataSource: Мастер-класс по Dip
 
RDSDataSource: YapDatabase
RDSDataSource: YapDatabaseRDSDataSource: YapDatabase
RDSDataSource: YapDatabase
 
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
 
Rambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеровRambler.iOS #8: Как не стать жертвой бэкендеров
Rambler.iOS #8: Как не стать жертвой бэкендеров
 
RDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperiencedRDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperienced
 
RDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDKRDSDataSource: Автогенерация документации для SDK
RDSDataSource: Автогенерация документации для SDK
 
RDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOSRDSDataSource: Плюрализация в iOS
RDSDataSource: Плюрализация в iOS
 
RDSDataSource: Promises
RDSDataSource: PromisesRDSDataSource: Promises
RDSDataSource: Promises
 
RDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwiftRDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwift
 
Rambler.iOS #7: Построение сложного табличного интерфейса
Rambler.iOS #7: Построение сложного табличного интерфейсаRambler.iOS #7: Построение сложного табличного интерфейса
Rambler.iOS #7: Построение сложного табличного интерфейса
 

Rambler.iOS #6: Pagination Demystified