Сотрудник Facebook Джонатан Дэнн написал в блоге, подробно описав, как команда разработчиков iOS компании проектировала ранние версии приложения Facebook для iPhone и какие масштабные работы по кодированию потребовались для переписывания нового приложения Facebook 5.0.
Пост отчасти технический, но его стоит прочитать разработчикам и всем, кто интересуется тем, как создается одно из самых популярных приложений для iPhone.
Отрывок:
Одним из самых больших преимуществ, которое мы получили от разработки нативной iOS, стала возможность сделать приложение быстрым. Теперь, прокручивая ленту новостей в новом Facebook для iOS, вы заметите, что оно работает намного быстрее, чем раньше. Один из способов, которым мы этого добились, — это перебалансировка выполнения определенных задач. Например, в iOS основной поток управляет пользовательским интерфейсом и обрабатывает события касания, поэтому чем больше работы мы выполняем в основном потоке, тем медленнее ощущается приложение. Вместо этого мы тщательно выполняем вычислительно сложные задачи в фоновом режиме. Это означает, что вся наша сетевая активность, разбор JSON, создание NSManagedObject и сохранение в диск никогда не касаются основного потока.
В качестве другого примера: мы используем Core Text для размещения многих наших строк, но расчеты компоновки могут быстро стать узким местом. В нашем новом приложении для iOS, когда мы загружаем новый контент, мы асинхронно рассчитываем размеры всех этих строк, кэшируем наши CTFramesetter (которые дорого создавать) и затем используем все эти расчеты позже, когда представляем историю в нашем UITableView.
Наконец, когда вы запускаете Facebook для iOS, вы хотите видеть свою ленту новостей, а не индикатор загрузки. Чтобы обеспечить наилучший возможный опыт, мы теперь сразу же показываем ранее закэшированный контент. Но это создает новую проблему: если в вашей ленте новостей много историй, UITableView создает небольшую проблему, вызывая метод делегата -tableView:heightForRowAtIndexPath: для каждой истории в вашей ленте новостей, чтобы определить, насколько высокой должна быть полоса прокрутки. Это привело бы к тому, что приложение загружало бы все данные истории с диска и рассчитывало бы всю компоновку истории только для того, чтобы вернуть высоту истории, что означало бы, что время запуска будет постепенно увеличиваться по мере накопления большего количества историй.
Решение этой конкретной проблемы состоит из двух основных частей. Во-первых, когда мы выполняем первоначальные асинхронные расчеты компоновки, мы также сохраняем высоту истории в Core Data. Таким образом, мы полностью избегаем расчета компоновки в -tableView:heightForRowAtIndexPath:. Во-вторых, мы разделили наш объект модели «история». Мы получаем только высоту истории (и несколько других вещей) с диска при запуске. Позже мы получаем остальные данные истории, и любые дополнительные расчеты компоновки, которые нам нужно выполнить, выполняются асинхронно.