Как мы знаем, Redis — документо-ориентированное сетевое журналируемое хранилище данных типа «ключ-значение» с открытым исходным кодом (так гласит источник). Все нижеследующее сделано «just for fun». Я не могу предложить применения Redis на iOS. Если у вас другая точка зрения — поделитесь в комментариях.

Подготовка

Идем на сайт Redis и ищем кнопку «Download». Загружаем исходники последней стабильной версии, в данный момент это 2.4.17. В архиве много всяких файлов, но нас интересует папка src. Как можно видеть из папки deps — у проекта есть некоторые зависимости. Но для сборки redis-server они не нужны. Судя по make-файлу, из исходников мы можем получить сам redis-server, бенчмарки, тесты и Command Line Interface. Осталось создать любой iOS проект в XCode.

Первая попытка

Просто перетянем папку src в XCode-проект, при этом игнорируем make-файл. Для начала будем собирать для iPhone Simulator. Жмем «Build» или Command-B. XCode выдаст много ошибок — первая (и самая простая) попытка провалилась. Можно, конечно-же, попробовать разобраться почему произошли эти ошибки, но я решил пойти другим путем.

Иной подход

Смело удаляем все файлы Redis из проекта. Откроем make-файл в папке src и посмотрим, что не все файлы из папки src нужны для сборки redis-server. Найдем вот такую строчку:

OBJ = adlist.o ae.o anet.o dict.o redis.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o vm.o pubsub.o multi.o debug.o sort.o intset.o syncio.o slowlog.o bio.o memtest.o

Получается, что нам в проект нужно добавить *.h и *.c файлы с такими именами. Что и предлагаю сделать. После того, как все файлы добавлены в проект, пробуем собрать. Пока ошибка всего одна: не хватает файла ae_kqueue.c. Добавим его в проект. Так же и с fmacros.h, version.h, endian.h. Но как бы мы ни старались, файла release.h мы не найдем. Для этого нужно запустить скрипт mkreleasehdr.sh из папки src, он сгенерирует файл release.h, который мы и добавим в проект.

Очередной раз жмем «Build» и видим что ошибки остались. Все они в файле ae_kqueue.h. Решается это добавлением:

#include "ae.h"
#include "zmalloc.h"
#include <unistd.h>

Правим код

Пробуем снова собрать. Обнаруживаем ошибку, что функция main в проекте у нас существует в двух местах. Оно-то и понятно, ведь redis-server хочет запускаться сам по себе. Открываем файл redis.c и изменяем имя функции main на redisMain, получиться вот так:

int redisMain(int argc, char **argv)

И ее объявление добавляем в файл redis.h. Пробуем собрать. Теперь проект должен собираться без ошибок и предупреждений.

Теперь нужно сделать, чтобы Redis стартовал при старте приложения. Откроем файл main.m и добавим:

#import "redis.h"

А так же добавим перед вызовом UIApplicationMain:

redisMain(argc, argv);

Запустим проект в симуляторе и увидим черный экран. Оно и не удивительно, ведь Redis однопоточен и он блокирует тот поток, в котором запущен. Поэтому стоит создать для него новый поток и запустить его там. Поэтому сделаем вот так:

dispatch_queue_t redisQueue = dispatch_queue_create("redis.queue", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(redisQueue, ^{
    redisMain(argc, argv);
});

Запускаем проект и видим радостные логи:

[1709] 06 Oct 16:36:23 # Warning: no config file specified, using the default config. In order to specify a config file use 'redis-server /path/to/redis.conf'
[1709] 06 Oct 16:36:23 # Warning: 32 bit instance detected but no memory limit set. Setting 3.5 GB maxmemory limit with 'noeviction' policy now.
[1709] 06 Oct 16:36:23 * Server started, Redis version 2.4.17
[1709] 06 Oct 16:36:23 * The server is now ready to accept connections on port 6379
[1709] 06 Oct 16:36:23 - 0 clients connected (0 slaves), 629440 bytes in use
2012-10-06 16:36:23.423 Redis[1709:c07] Application windows are expected to have a root view controller at the end of application launch
[1709] 06 Oct 16:36:28 - 0 clients connected (0 slaves), 629440 bytes in use

Еще немного изменений

А теперь пробуем запустить на девайсе. Но встречаем такую ошибку:

redis.c:1835:42: No member named '__eip' in 'struct __darwin_arm_thread_state'

Найдем место, где возникает эта ошибка, это строчка

return (void*) uc->uc_mcontext->__ss.__eip;

в функции

static void *getMcontextEip(ucontext_t *uc)

По-видимому это какая-то платформозавимая инструкция. Я не специалист в архитектуре ARM, поэтому не нашел ничего лучшего чем заменить эту строчку на:

return NULL;

Я считаю, ничего плохого не случилось, т.к. функция getMcontextEip используется для вывода стека вызова при возникновении ошибки.

Пробуем еще раз запустить на девайсе — приложение должно заработать.

Пробуем

Для проверки работы Redis на девайсе соберем redis-cli. Зайдите в папку src и наберите комманду:

make redis-cli

Затем:

./redis-cli IP-адрес-телефона

Нужно чтобы телефон и компьютер находился в одной сети.

Если вы все сделали правильно, в логе приложения вы увидите что-то вроде:

[3631] 06 Oct 16:49:22 - Accepted 192.168.1.2:55165
[3631] 06 Oct 16:49:26 - 1 clients connected (0 slaves), 637328 bytes in use

Итоги

Как мы знаем, Redis хранит все данные в оперативной памяти, поэтому рассчитывать на постоянное хранение данных не приходиться. Конечно же, Redis умеет сбрасывать данные в файл, а затем при старте его считывать. Но все равно это не может является супер-альтернативой хранения данных в iOS. Для этого стоит использовать CoreData. Если очень хочется хранить данные в оперативной памяти — CoreData это умеет тоже.

Если вам стало интересно — можем продолжить…

Проект можно загрузить отсюда.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *