понедельник, 10 сентября 2012 г.

Недолгий век UISearchDisplayController


Объект UISearchDisplayController инициализируется вызовом initWithSearchBar:contentsController:. Как видно из названия метода и документации, работающему контроллеру необходимо задать searchBar и contentController, в виде которого будет отображаться таблица с результатами поиска.
Покопавшись в документации UIViewController мы также увидим read-only свойство searchDisplayController.
Это значит, что мы не можем задать нашему основному контроллеру searchDisplayController напрямую, вместо этого мы должны инициализировать объект UISearchDisplayController с основным контроллером.
Ситуация стандартная, таким же образом мы действуем, когда создаем UINavigationController - не назначаем его основному контроллеру, а инициируем объект UINavigationController с основным контроллером.
Что может ввести в заблуждение, так это то, что обладание ссылкой searchDisplayController достаточно для работы. Но это не так, потому что во избежание зацикливания ссылок контроллеров друг на друга объект UISearchDisplayController "умирает" спустя некоторое время после создания.
Говоря проще, создавая UISearchDisplayController во viewDidLoad вы теряете его сразу по завершению метода.
Выход прост: создать отдельное strong-свойство в основном контроллере для объекта UISearchDisplayController. Правда, остается непонятным, зачем тогда вообще ссылка searchDisplayController - ведь в отличие от UINavigationController он связан только с одним контроллером за раз.

понедельник, 16 июля 2012 г.

Core Data. Запрос с сортировкой не любит потоки.

Как известно, Core Data - отличный инструмент для работы с данными большого объема на уровне объектов. Core Data позволяет производить различные операции с контекстами на разных потоках, исходя из правила "один контекст на один поток".
Рядовая ситуация - контекст на главном потоке и "фоновый" контекст на фоновом потоке.
После проведения операция на фоновом потоке и сохранения, назначение sortDescriptors объектам NSFetchRequest не принесет ожидаемого результат. Мне не понятно, чем вызвано такое поведение, но факт остается фактом - использовать массив из NSSortDescriptor объектов для включения сортировки в запрос - тщетное дело. Информации по этому вопросу не очень много, но из того что я смог собрать стало ясно следующее:

  1. Поведение различно на iOS 4 и iOS 5 (iOS 6 не проверял).
  2. Некоторым помогает сохранение главного контекста.
  3. Необходимо следить за тем, чтобы контекст сохранялся на своем потоке. Иными словами, основной контекст всегда будет блокировать интерфейс приложения (поскольку существует на главном потоке).
  4. Если после сохранения контекстов (рекурсивное, сохраняя "фоновые" контексты, "вливая" изменения в основной контекст и сохраняя его в непосредственное хранилище данных) внести изменения в контекст (я добавлял новые объекты), сортировка запроса вновь начнет работать.
  5. Чтобы гарантировано получать сортированный массив можно сортировать массив, получаемый в результате выполнения запроса без сортировки.
  6. NSPredicate работает без проблем. Это прекрасно, потому что он куда важнее NSSortDescriptor (поскольку правильно описанный предикат - это эффективность SQL-запросов).
Кое-что по делу:

Автор смог решить проблему последовательным сохранением контекстов, реализованным в Magical Record. Я долго бился над пробным приложением и мой результат был менее радостным - сортировка не работала.

Более плачевный результат, когда выполнение запроса влекло за собой Bad Access. Автор не приводит код, поэтому есть вероятность, что это дело - результат неаккуратного обращения с памятью. Но тот факт, что сортировка готовых данных проходит без каких-либо ошибок указывает на то, что проблема имеет по крайней мере схожий корень с описанным выше случаем.

Непредсказуемый NSURLConnectionDownloadDelegate

NSURLConnectionDownloadDelegate сменил на посту NSURLDataDelegate () и привнес немало радости iOS-пограммистам, пытавшимся использовать новый делегатный метод – connectionDidFinishDownloading:destinationURL:, потому как получаемый URL указывал на несуществующий файл, в том случае, если файл имел расширение JPG или PDF.
Более подробно на Stackoverflow: