Я разработчик iOS с некоторым опытом, и этот вопрос мне действительно интересен. Я видел много разных ресурсов и материалов на эту тему, но, тем не менее, я все еще в замешательстве. Какова лучшая архитектура для сетевого приложения iOS? Я имею в виду базовую абстрактную структуру, шаблоны, которые подойдут каждому сетевому приложению, будь то небольшое приложение с несколькими запросами к серверу или сложный клиент REST. Apple рекомендует использовать MVC
в качестве базового архитектурного подхода для всех приложений iOS, но ни MVC
более, ни более современные MVVM
шаблоны не объясняют, где размещать код сетевой логики и как его организовать в целом.
Нужно ли разрабатывать что-то вроде MVCS
( S
для Service
) и на этом Service
уровне помещать все API
запросы и другую сетевую логику, которая в перспективе может быть действительно сложной? После некоторого исследования я нашел два основных подхода к этому. Здесь было рекомендовано создать отдельный класс для каждого сетевого запроса к веб-службе API
(например, LoginRequest
класс или PostCommentRequest
класс и т. Д.), Который все наследует от абстрактного класса базового запроса, AbstractBaseRequest
и, кроме того, создать некоторый глобальный сетевой менеджер, который инкапсулирует общий сетевой код и другие предпочтения (это может быть AFNetworking
настройка илиRestKit
настройка, если мы имеем сложные сопоставления объектов и персистентность, или даже собственную сетевую коммуникационную реализацию со стандартным API). Но такой подход кажется мне непосильным. Другой подход заключается в каком - то одноплодный API
диспетчере или класс менеджера , как и в первом подходе, но не создавать классы для каждого запроса и вместо того, чтобы инкапсулировать каждый запрос как метод экземпляр этого публичного менеджера класса , как: fetchContacts
, loginUser
методы и т.д. Итак, что самый лучший и правильный путь? Есть ли другие интересные подходы, которые я еще не знаю?
И должен ли я создать еще один слой для всех этих сетевых вещей, таких как Service
, или NetworkProvider
слой, или что-то еще поверх моей MVC
архитектуры, или этот слой должен быть интегрирован (внедрен) в существующие MVC
уровни, например Model
?
Я знаю, что существуют прекрасные подходы, или как тогда такие мобильные монстры, как клиент Facebook или клиент LinkedIn, справляются с экспоненциально растущей сложностью сетевой логики?
Я знаю, что нет точного и формального ответа на проблему. Цель этого вопроса - собрать наиболее интересные подходы от опытных разработчиков iOS . Лучший предложенный подход будет помечен как принятый и награжден заслуженной репутацией, за других проголосуют. Это в основном теоретический и исследовательский вопрос. Я хочу понять базовый, абстрактный и правильный архитектурный подход для сетевых приложений в iOS. Надеюсь на подробное объяснение от опытных разработчиков.
источник
Ответы:
I want to understand basic, abstract and correct architectural approach for networking applications in iOS
: Нет нет «лучшего» или «самого правильного» подхода для построения архитектуры приложения. Это очень творческая работа. Вы всегда должны выбирать наиболее простую и расширяемую архитектуру, которая будет понятна любому разработчику, начинающему работать над вашим проектом, или другим разработчикам в вашей команде, но я согласен, что могут быть «хорошие» и «плохие» "архитектура.Вы сказали: «
collect the most interesting approaches from experienced iOS developers
Я не думаю, что мой подход является наиболее интересным или правильным, но я использовал его в нескольких проектах и доволен им. Это гибридный подход из тех, что вы упомянули выше, а также с улучшениями из моих собственных исследований. Я интересуюсь проблемами построения подходов, которые сочетают в себе несколько известных шаблонов и идиом. Я думаю, что многие корпоративные модели Фаулера могут быть успешно применены к мобильным приложениям. Вот список наиболее интересных из них, которые мы можем применить для создания архитектуры приложения iOS ( на мой взгляд ): уровень обслуживания , единица работы , удаленный фасад , объект передачи данных ,Шлюз , Супертип слоя , Особый случай , Модель предметной области . Вы всегда должны правильно проектировать слой модели и не забывать о постоянстве (это может значительно повысить производительность вашего приложения). Вы можете использоватьCore Data
для этого. Но вы не должны забывать, чтоCore Data
это не ORM или база данных, а диспетчер графов объектов с хорошим постоянством. Таким образом, очень часто этоCore Data
может быть слишком тяжело для ваших нужд, и вы можете посмотреть на новые решения, такие как Realm и Couchbase Lite , или создать свой собственный облегченный слой отображения / сохранения объектов, основанный на необработанном SQLite или LevelDB, Также я советую вам ознакомиться с Domain Driven Design и CQRS .Сначала, я думаю, мы должны создать еще один слой для сетей, потому что нам не нужны жирные контроллеры или тяжелые, перегруженные модели. Я не верю в эти
fat model, skinny controller
вещи. Но я верю вskinny everything
подход, потому что ни один класс не должен быть толстым, никогда. Все сети могут быть в целом абстрагированы как бизнес-логика, следовательно, у нас должен быть другой уровень, на котором мы можем его разместить. Сервисный уровень - это то, что нам нужно:В нашей
MVC
сфереService Layer
нечто вроде посредника между моделью домена и контроллерами. Существует довольно похожий вариант этого подхода, называемый MVCS, где aStore
фактически является нашимService
уровнем.Store
торгует моделями экземпляров и управляет сетью, кэшированием и т. д. Я хочу упомянуть, что вам не следует записывать всю свою сетевую и бизнес-логику на уровне обслуживания. Это также можно считать плохим дизайном. Для получения дополнительной информации посмотрите модели доменов Anemic и Rich . Некоторые сервисные методы и бизнес-логика могут быть обработаны в модели, поэтому это будет «богатая» (с поведением) модель.Я всегда широко использую две библиотеки: AFNetworking 2.0 и ReactiveCocoa . Я думаю, что это необходимо для любого современного приложения, которое взаимодействует с сетью и веб-сервисами или содержит сложную логику пользовательского интерфейса.
АРХИТЕКТУРА
Сначала я создаю общий
APIClient
класс, который является подклассом AFHTTPSessionManager . Это рабочая лошадка всей сети в приложении: все классы обслуживания делегируют ему фактические запросы REST. Он содержит все настройки HTTP-клиента, которые мне нужны в конкретном приложении: SSL-закрепление, обработка ошибок и создание простыхNSError
объектов с подробными причинами сбоев и описаниями всехAPI
и ошибок подключения (в таком случае контроллер сможет отображать правильные сообщения для пользователь), настройка сериализаторов запросов и ответов, http-заголовков и прочего, связанного с сетью. Тогда я логически разделить все запросы API в подсервисы или, вернее, microservices :UserSerivces
,CommonServices
,SecurityServices
,FriendsServices
и так далее, в соответствии с бизнес-логикой, которую они реализуют. Каждый из этих микросервисов является отдельным классом. Они вместе образуютService Layer
. Эти классы содержат методы для каждого запроса API, обрабатывают модели предметной области и всегда возвращают aRACSignal
с проанализированной моделью ответа илиNSError
вызывающей стороне.Я хочу упомянуть, что если у вас сложная логика сериализации модели - тогда создайте для нее еще один слой: что-то вроде Data Mapper, но более общего, например, JSON / XML -> Model Mapper . Если у вас есть кеш: создайте его как отдельный слой / службу (не следует смешивать бизнес-логику с кешированием). Зачем? Потому что правильный кеширующий слой может быть довольно сложным с собственными ошибками. Люди реализуют сложную логику, чтобы получить правильное и предсказуемое кэширование, например, моноидальное кэширование с проекциями, основанными на профункторах. Вы можете прочитать об этой прекрасной библиотеке под названием Карлос, чтобы понять больше. И не забывайте, что Core Data действительно может помочь вам со всеми проблемами кэширования и позволит вам писать меньше логики. Кроме того, если у вас есть некоторая логика между
NSManagedObjectContext
моделями запросов к серверу, вы можете использоватьШаблон репозитория , который отделяет логику, которая извлекает данные, и сопоставляет ее с моделью сущностей от бизнес-логики, действующей на модели. Поэтому я советую использовать шаблон репозитория, даже если у вас есть архитектура на основе Core Data. Repository тазов абстрактные вещи, какNSFetchRequest
,NSEntityDescription
,NSPredicate
и так далее для простых методов , таких какget
илиput
.После всех этих действий на сервисном уровне вызывающая сторона (контроллер представления) может выполнить некоторые сложные асинхронные действия с ответом: манипулирование сигналом, сцепление, отображение и т. Д. С помощью
ReactiveCocoa
примитивов или просто подписаться на него и показать результаты в представлении. , Я впрыснуть с Injection Dependency во всех этих службах классов моихAPIClient
, которая переведет конкретный вызов службы в соответствующемGET
,POST
,PUT
,DELETE
и т.д. запрос на REST конечной точку. В этом случаеAPIClient
неявно передается всем контроллерам, вы можете сделать это явно с параметризацией поAPIClient
классам обслуживания. Это может иметь смысл, если вы хотите использовать различные настройкиAPIClient
для определенных классов обслуживания, но если по каким-то причинам вам не нужны дополнительные копии или вы уверены, что всегда будете использовать один конкретный экземпляр (без настроек)APIClient
- сделайте его одиночным, но НЕ делайте, пожалуйста, НЕ Занимаюсь обслуживанием в качестве одиночек.Затем каждый контроллер представления снова с помощью DI вводит необходимый ему класс обслуживания, вызывает соответствующие методы обслуживания и объединяет их результаты с логикой пользовательского интерфейса. Для внедрения зависимостей мне нравится использовать BloodMagic или более мощный фреймворк Typhoon . Я никогда не использую одиночные игры, уроки Бога
APIManagerWhatever
или другие неправильные вещи. Потому что если вы звоните своему классуWhateverManager
, это указывает на то, что вы не знаете его цели, и это плохой выбор дизайна . Singletons также является анти-паттерном, и в большинстве случаев (кроме редких) это неправильное решение. Синглтон следует рассматривать только в том случае, если выполнены все три из следующих критериев:В нашем случае владение отдельным экземпляром не является проблемой, и нам также не нужен глобальный доступ после того, как мы разделили нашего God Manager на сервисы, потому что теперь только один или несколько выделенных контроллеров нуждаются в конкретной услуге (например,
UserProfile
контроллере нужныUserServices
и т. Д.) ,Мы всегда должны соблюдать
S
принцип SOLID и использовать разделение интересов , поэтому не объединяйте все свои методы обслуживания и вызовы сетей в одном классе, потому что это безумие, особенно если вы разрабатываете крупное корпоративное приложение. Вот почему мы должны учитывать внедрение зависимостей и сервисный подход. Я считаю этот подход современным и пост-оо . В этом случае мы разделяем наше приложение на две части: управляющую логику (контроллеры и события) и параметры.Вот общий рабочий процесс моей архитектуры на примере. Предположим, у нас есть
FriendsViewController
список друзей пользователя, который можно удалить из списка друзей. Я создаю метод в своемFriendsServices
классе под названием:где
Friend
- объект модели / домена (или это может быть простоUser
объект, если они имеют похожие атрибуты). Underhood этого метода разборовFriend
доNSDictionary
параметров JSONfriend_id
,name
,surname
,friend_request_id
и так далее. Я всегда использую библиотеку Mantle для такого рода шаблонов и для моего модельного уровня (разбор вперед и назад, управление иерархиями вложенных объектов в JSON и т. Д.). После разбора он вызываетAPIClient
DELETE
метод , чтобы сделать фактический запрос REST и возвращаетсяResponse
вRACSignal
вызывающей программе (FriendsViewController
в нашем случае) , чтобы отобразить соответствующее сообщение для пользователя или любой другой .Если наше приложение очень большое, мы должны отделить нашу логику еще яснее. Например, не всегда хорошо смешивать
Repository
или моделировать логику сService
одним. Когда я описывал свой подход, я говорил, чтоremoveFriend
метод должен быть наService
уровне, но если мы будем более педантичными, мы можем заметить, что он лучше принадлежитRepository
. Давайте вспомним, что такое репозиторий. Эрик Эванс дал точное описание в своей книге [DDD]:Таким образом, a
Repository
по сути является фасадом, который использует семантику стиля Collection (Add, Update, Remove) для предоставления доступа к данным / объектам. Вот почему , когда у вас есть что - то вроде:getFriendsList
,getUserGroups
,removeFriend
вы можете поместить его вRepository
, поскольку сбор подобной семантике довольно ясно здесь. И код как:это определенно бизнес-логика, потому что она выходит за рамки базовых
CRUD
операций и соединяет два объекта домена (Friend
иRequest
), поэтому она должна быть размещена наService
уровне. Также хочу заметить: не создавайте ненужных абстракций . Используйте все эти подходы с умом. Потому что если вы переполните свое приложение абстракциями, это увеличит его случайную сложность, и сложность вызывает больше проблем в программных системах, чем что-либо ещеЯ описываю вам «старый» пример Objective-C, но этот подход может быть очень легко адаптирован для языка Swift с гораздо большим количеством улучшений, потому что он имеет больше полезных функций и функциональных возможностей. Я настоятельно рекомендую использовать эту библиотеку: Моя . Позволяет создать более элегантный
APIClient
слой (наша рабочая лошадка, как вы помните). Теперь нашимAPIClient
провайдером будет тип значения (enum) с расширениями, соответствующими протоколам и использующими сопоставление с образцом деструктуризации. Быстрое перечисление + сопоставление с образцом позволяет нам создавать алгебраические типы данных, как в классическом функциональном программировании. Наши микросервисы будут использовать этого улучшенногоAPIClient
поставщика, как в обычном подходе Objective-C. Для слоя модели вместоMantle
вы можете использовать библиотеку ObjectMapperили мне нравится использовать более элегантную и функциональную библиотеку Argo .Итак, я описал свой общий архитектурный подход, который, я думаю, можно адаптировать для любого приложения. Конечно, может быть намного больше улучшений. Я советую вам изучить функциональное программирование, потому что вы можете извлечь из этого много пользы, но и не заходите слишком далеко. Устранение чрезмерного общего разделяемого глобального изменчивого состояния, создание модели неизменяемого домена или создание чистых функций без внешних побочных эффектов, как правило, является хорошей практикой, и новый
Swift
язык поощряет это. Но всегда помните, что перегружая ваш код тяжелыми чисто функциональными шаблонами, теоретико-категоричные подходы - плохая идея, потому что другие разработчики будут читать и поддерживать ваш код, и они могут быть разочарованы или напуганыprismatic profunctors
и такие вещи в вашей неизменной модели. То же самое сReactiveCocoa
: не слишком многоRACify
кода , потому что он может стать нечитаемым очень быстро, особенно для новичков. Используйте его, когда это действительно может упростить ваши цели и логику.Так,
read a lot, mix, experiment, and try to pick up the best from different architectural approaches
. Это лучший совет, который я могу вам дать.источник
". I don't like singletons. I have an opinion that if you decided to use singletons in your project you should have at least three criteria why you do this (I edited my answer). So I inject them (lazy of course and not each time, but
раз `) в каждом контроллере.В соответствии с целью этого вопроса, я хотел бы описать наш архитектурный подход.
Архитектурный подход
Архитектура нашего общего применения Иос стоит на следующих моделей: Обслуживание слоев , MVVM , Связывание UI данных , Dependency Injection ; и парадигма функционально-реактивного программирования .
Мы можем разделить типичное потребительское приложение на следующие логические уровни:
Сборочный слой является начальной точкой нашего приложения. Он содержит контейнер внедрения зависимостей и объявления объектов приложения и их зависимостей. Этот слой также может содержать конфигурацию приложения (URL, сторонние сервисные ключи и т. Д.). Для этого мы используем библиотеку Тайфун .
Слой модели содержит классы моделей доменов, проверки, сопоставления. Мы используем библиотеку Mantle для отображения наших моделей: она поддерживает сериализацию / десериализацию в
JSON
формат иNSManagedObject
модели. Для проверки и представления формы наших моделей мы используем библиотеки FXForms и FXModelValidation .Сервисный уровень объявляет сервисы, которые мы используем для взаимодействия с внешними системами с целью отправки или получения данных, которые представлены в нашей модели предметной области. Поэтому обычно у нас есть службы для связи с серверными API-интерфейсами (для каждой сущности), службами обмена сообщениями (например, PubNub ), службами хранения (например, Amazon S3) и т. Д. В основном службы обертывают объекты, предоставляемые SDK (например, PubNub SDK), или реализуют свои собственные средства связи. логика. Для общих сетей мы используем библиотеку AFNetworking .
Цель уровня хранения - организовать локальное хранение данных на устройстве. Для этого мы используем Core Data или Realm (у обоих есть свои плюсы и минусы, решение о том, что использовать, основано на конкретных спецификациях). Для настройки Core Data мы используем библиотеку MDMCoreData и несколько классов - хранилищ (аналогично сервисам), которые предоставляют доступ к локальному хранилищу для каждого объекта. Для Realm мы просто используем подобные хранилища, чтобы иметь доступ к локальному хранилищу.
Слой менеджеров - это место, где живут наши абстракции / оболочки.
В роли менеджера может быть:
Таким образом, в роли менеджера может выступать любой объект, реализующий логику определенного аспекта или задачи, необходимую для работы приложения.
Мы стараемся избегать синглетонов, но этот слой - место, где они живут, если они необходимы.
Слой Coordinators предоставляет объекты, которые зависят от объектов других слоев (Service, Storage, Model), чтобы объединить их логику в одну последовательность работы, необходимую для определенного модуля (функция, экран, пользовательская история или пользовательский опыт). Обычно он объединяет асинхронные операции и знает, как реагировать на их успехи и неудачи. В качестве примера вы можете представить функцию обмена сообщениями и соответствующий
MessagingCoordinator
объект. Обработка операции отправки сообщения может выглядеть так:На каждом из вышеперечисленных шагов ошибка обрабатывается соответственно.
Слой пользовательского интерфейса состоит из следующих подслоев:
Чтобы избежать Massive View Controllers, мы используем шаблон MVVM и реализуем логику, необходимую для представления пользовательского интерфейса во ViewModels. ViewModel обычно имеет координаторов и менеджеров в качестве зависимостей. ViewModels, используемые ViewControllers и некоторыми видами представлений (например, ячейки табличного представления). Склеивание между ViewControllers и ViewModels - это привязка данных и шаблон команд. Для того, чтобы получить этот клей, мы используем библиотеку ReactiveCocoa .
Мы также используем ReactiveCocoa и его
RACSignal
концепцию в качестве интерфейса и типа возвращаемого значения для всех координаторов, служб, методов хранилищ. Это позволяет нам связывать операции, запускать их параллельно или последовательно, а также многие другие полезные вещи, предоставляемые ReactiveCocoa.Мы пытаемся реализовать наше поведение пользовательского интерфейса декларативным способом. Привязка данных и автоматическое расположение очень помогают в достижении этой цели.
Уровень инфраструктуры содержит все помощники, расширения, утилиты, необходимые для работы приложения.
Этот подход хорошо работает для нас и тех типов приложений, которые мы обычно создаем. Но вы должны понимать, что это всего лишь субъективный подход, который следует адаптировать / изменить для целей конкретной команды.
Надеюсь, что это поможет вам!
Также вы можете найти более подробную информацию о процессе разработки iOS в этом блоге. IOS Development as a Service
источник
Поскольку все приложения для iOS различны, я думаю, что здесь есть разные подходы, но я обычно так
и делаю: создаю класс центрального менеджера (singleton) для обработки всех запросов API (обычно называемых APICommunicator), и каждый метод экземпляра является вызовом API. , И есть один центральный (не публичный) метод:
Для записи я использую 2 основных библиотеки / фреймворка, ReactiveCocoa и AFNetworking. ReactiveCocoa отлично справляется с асинхронными сетевыми ответами, что вы можете сделать (sendNext :, sendError: и т. Д.).
Этот метод вызывает API, получает результаты и отправляет их через RAC в «сыром» формате (например, NSArray, который возвращает AFNetworking).
Затем метод,
getStuffList:
который вызвал вышеуказанный метод, подписывается на его сигнал, анализирует необработанные данные на объекты (с чем-то вроде Motis) и отправляет объекты один за другим вызывающей стороне (getStuffList:
и аналогичные методы также возвращают сигнал, на который контроллер может подписаться ).Подписанный контроллер получает объекты по
subscribeNext:
блоку и обрабатывает их.Я пробовал много способов в разных приложениях, но этот работал лучше всего из всех, поэтому я недавно использовал его в нескольких приложениях, он подходит как для небольших, так и для больших проектов, и его легко расширять и поддерживать, если что-то нужно изменить.
Надеюсь, это поможет, я хотел бы услышать мнение других о моем подходе и, возможно, как другие думают, что это может быть улучшено.
источник
+ (void)getAllUsersWithSuccess:(void(^)(NSArray*))success failure:(void(^)(NSError*))failure;
и- (void)postWithSuccess:(void(^)(instancetype))success failure:(void(^)(NSError*))failure;
которые делают необходимые приготовления , а затем вызвать через менеджеру API.В моей ситуации я обычно использую библиотеку ResKit для настройки сетевого уровня. Обеспечивает простой в использовании анализ. Это уменьшает мои усилия по настройке сопоставления для разных ответов и прочего.
Я только добавляю некоторый код, чтобы настроить отображение автоматически. Я определяю базовый класс для своих моделей (не протокол из-за большого количества кода, чтобы проверить, реализован ли какой-либо метод или нет, и меньше кода в самих моделях):
MappableEntry.h
MappableEntry.m
Отношения - это объекты, которые представляют вложенные объекты в ответ:
RelationshipObject.h
RelationshipObject.m
Затем я настраиваю отображение для RestKit следующим образом:
ObjectMappingInitializer.h
ObjectMappingInitializer.m
Некоторые примеры реализации MappableEntry:
user.h
User.m
Теперь о упаковке запросов:
У меня есть заголовочный файл с определением блоков, чтобы уменьшить длину строки во всех классах APIRequest:
APICallbacks.h
И пример моего класса APIRequest, который я использую:
LoginAPI.h
LoginAPI.m
И все, что вам нужно сделать в коде, просто инициализировать объект API и вызывать его всякий раз, когда вам это нужно:
SomeViewController.m
Мой код не идеален, но его легко установить один раз и использовать для разных проектов. Если это кому-то интересно, я бы мог потратить некоторое время и сделать для него универсальное решение где-нибудь на GitHub и CocoaPods.
источник
На мой взгляд, вся архитектура программного обеспечения определяется необходимостью. Если это для обучения или личных целей, то определите основную цель и задайте ей архитектуру. Если это работа по найму, то бизнес-необходимость имеет первостепенное значение. Хитрость заключается в том, чтобы не позволить блестящим вещам отвлечь вас от реальных потребностей. Мне трудно это сделать. В этом бизнесе всегда появляются новые блестящие вещи, и многие из них бесполезны, но вы не всегда можете сказать это заранее. Сосредоточьтесь на необходимости и будьте готовы отказаться от неправильного выбора, если можете.
Например, недавно я сделал быстрый прототип приложения для обмена фотографиями для местного бизнеса. Поскольку бизнес-необходимость заключалась в том, чтобы сделать что-то быстрое и грязное, архитектура в конечном итоге представляла собой некоторый код iOS для вызова камеры и некоторый сетевой код, присоединенный к кнопке отправки, которая загружала изображение в хранилище S3 и записывала его в домен SimpleDB. Код был тривиальным, а стоимость минимальной, и у клиента есть масштабируемая коллекция фотографий, доступная через Интернет с помощью вызовов REST. Дешевое и глупое, приложение имело много недостатков и иногда блокировало пользовательский интерфейс, но было бы бесполезно делать больше для прототипа, и это позволяло бы им развертывать свои кадры и легко генерировать тысячи тестовых изображений без производительности или масштабируемости. проблемы. Дрянная архитектура, но она подходит по необходимости и стоит отлично.
Другой проект включал реализацию локальной защищенной базы данных, которая синхронизируется с системой компании в фоновом режиме, когда сеть доступна. Я создал фоновый синхронизатор, который использовал RestKit, так как в нем было все, что мне нужно. Но мне пришлось написать так много пользовательского кода для RestKit, чтобы иметь дело с уникальным JSON, что я мог бы сделать все это быстрее, написав свой собственный преобразование JSON в CoreData. Однако заказчик захотел принести это приложение на себя, и я чувствовал, что RestKit будет похож на фреймворки, которые они использовали на других платформах. Я жду, чтобы увидеть, было ли это хорошее решение.
Опять же, проблема для меня заключается в том, чтобы сосредоточиться на необходимости и позволить этому определять архитектуру. Я стараюсь изо всех сил избегать использования сторонних пакетов, поскольку они приносят затраты, которые появляются только после того, как приложение находится в поле некоторое время. Я стараюсь избегать создания иерархий классов, поскольку они редко окупаются. Если я могу написать что-то в разумные сроки вместо того, чтобы принять пакет, который не подходит идеально, тогда я сделаю это. Мой код хорошо структурирован для отладки и соответствующим образом прокомментирован, но сторонние пакеты редко встречаются. С учетом сказанного, я считаю, что AF Networking слишком полезен, чтобы его игнорировать, хорошо структурировать, хорошо комментировать и поддерживать, и я его часто использую! RestKit покрывает много общих случаев, но я чувствую, что я дрался, когда использую его, и большинство источников данных, с которыми я сталкиваюсь, полны причуд и проблем, которые лучше всего решать с помощью пользовательского кода. В моих последних нескольких приложениях я просто использую встроенные конвертеры JSON и пишу несколько служебных методов.
Один шаблон, который я всегда использую, состоит в том, чтобы получать сетевые вызовы от основного потока. Последние 4-5 приложений, которые я сделал, настроили фоновую задачу таймера, используя dispatch_source_create, который периодически просыпается и выполняет сетевые задачи по мере необходимости. Вы должны выполнить некоторую работу по обеспечению безопасности потоков и убедиться, что код, изменяющий пользовательский интерфейс, отправляется в основной поток. Это также помогает выполнить вход / инициализацию таким образом, чтобы пользователь не чувствовал себя обремененным или задержанным. Пока это работает довольно хорошо. Я предлагаю изучить эти вещи.
Наконец, я думаю, что по мере того, как мы будем больше работать и развивать ОС, мы будем стремиться к разработке более эффективных решений. Мне потребовались годы, чтобы преодолеть мою веру в то, что я должен следовать шаблонам и конструкциям, которые, по мнению других людей, являются обязательными. Если я работаю в контексте, где это является частью местной религии, хм, я имею в виду лучшие инженерные практики департамента, тогда я следую обычаям, которые они мне платят. Но я редко нахожу, что следование старым проектам и моделям является оптимальным решением. Я всегда стараюсь смотреть на решение сквозь призму потребностей бизнеса и строить архитектуру, которая бы соответствовала ему и оставляла все как можно проще. Когда я чувствую, что там недостаточно, но все работает правильно, тогда я на правильном пути.
источник
Я использую подход, который я получил здесь: https://github.com/Constantine-Fry/Foursquare-API-v2 . Я переписал эту библиотеку в Swift, и вы можете увидеть архитектурный подход из этих частей кода:
По существу, существует подкласс NSOperation, который создает NSURLRequest, анализирует ответ JSON и добавляет блок обратного вызова с результатом в очередь. Основной класс API создает NSURLRequest, инициализирует этот подкласс NSOperation и добавляет его в очередь.
источник
Мы используем несколько подходов в зависимости от ситуации. Для большинства вещей AFNetworking - это самый простой и надежный подход в том, что вы можете устанавливать заголовки, загружать многокомпонентные данные, использовать GET, POST, PUT & DELETE, и есть множество дополнительных категорий для UIKit, которые позволяют вам, например, установить изображение из URL В сложном приложении с большим количеством вызовов мы иногда абстрагируем это до собственного удобного метода, который будет выглядеть примерно так:
Есть несколько ситуаций, когда AFNetworking не подходит, например, когда вы создаете инфраструктуру или другой компонент библиотеки, поскольку AFNetworking уже может быть в другой кодовой базе. В этой ситуации вы использовали бы NSMutableURLRequest либо встроенным, если вы делаете один вызов, либо абстрагируете в класс запроса / ответа.
источник
Я избегаю одиночек при разработке своих приложений. Они типичны для многих людей, но я думаю, что вы можете найти более элегантные решения в других местах. Обычно я создаю свои сущности в CoreData, а затем помещаю свой код REST в категорию NSManagedObject. Если, например, я хочу создать и отправить нового пользователя, я бы сделал это:
Я использую RESTKit для сопоставления объектов и инициализирую его при запуске. Я считаю, что маршрутизация всех ваших звонков через один канал - пустая трата времени и добавляет много ненужных шаблонов.
В NSManagedObject + Extensions.m:
В NSManagedObject + Networking.m:
Зачем добавлять дополнительные вспомогательные классы, когда вы можете расширить функциональность общего базового класса с помощью категорий?
Если вы заинтересованы в более подробной информации о моем решении, дайте мне знать. Я рад поделиться.
источник
Попробуйте https://github.com/kevin0571/STNetTaskQueue
Создавайте запросы API в отдельных классах.
STNetTaskQueue будет работать с потоками и делегировать / обратный вызов.
Выдвижной для разных протоколов.
источник
С чисто классовой точки зрения у вас обычно будет что-то вроде этого:
Класс модели данных - это действительно зависит от того, сколько реальных сущностей вы имеете дело, и как они связаны.
Например, если у вас есть массив элементов для отображения в четырех разных представлениях (список, диаграмма, график и т. Д.), У вас будет один класс модели данных для списка элементов, и еще один для элемента. Список класса элемента будет разделен четыре контроллеров зрения - все дети контроллера панели вкладок или контроллера нав.
Классы модели данных пригодятся не только для отображения данных, но и для их сериализации, где каждый из них может представлять свой собственный формат сериализации с помощью методов экспорта JSON / XML / CSV (или чего-либо еще).
Важно понимать, что вам также нужны классы построителя запросов API, которые сопоставляются напрямую с вашими конечными точками API REST. Допустим, у вас есть API, который регистрирует пользователя - поэтому ваш класс конструктора API входа создаст полезную нагрузку POST JSON для API входа в систему. В другом примере класс построителя запросов API для списка элементов каталога API создаст строку запроса GET для соответствующего API и запустит запрос REST GET.
Эти классы построителя запросов API обычно получают данные от контроллеров представления, а также передают те же данные обратно в контроллеры представления для обновления пользовательского интерфейса / других операций. Затем контроллеры представлений решат, как обновить объекты модели данных этими данными.
Наконец, сердце клиента REST - класс средства извлечения данных API, который не обращает внимания на все виды запросов API, которые делает ваше приложение. Этот класс, скорее всего, будет синглтоном, но, как отмечали другие, он не обязательно должен быть синглтоном.
Обратите внимание, что ссылка является просто типичной реализацией и не принимает во внимание сценарии, такие как сеанс, файлы cookie и т. Д., Но этого достаточно, чтобы начать работу без использования сторонних сред.
источник
На этот вопрос уже есть много отличных и обширных ответов, но я чувствую, что должен упомянуть об этом, потому что никто больше не имеет.
Alamofire для Swift. https://github.com/Alamofire/Alamofire
Он создан теми же людьми, что и AFNetworking, но более непосредственно разработан с учетом Swift.
источник
Я думаю, что сейчас средний проект использует архитектуру MVVM, а Большой проект использует архитектуру VIPER и пытается достичь
Архитектурные подходы для создания сетевых приложений iOS (клиенты REST)
Разделение заботы о чистом и читаемом коде во избежание дублирования:
инверсия зависимости
Основная ответственность:
Здесь вы найдете архитектуру GitHub MVVM с остальным API Swift Project
источник
В разработке мобильного программного обеспечения наиболее широко используются шаблоны «Чистая архитектура» + «MVVM» и «Redux».
Чистая архитектура + MVVM состоит из 3 уровней: домен, презентация, уровни данных. Где уровень представления и уровень хранилища данных зависят от уровня домена:
А презентационный слой состоит из ViewModels и Views (MVVM):
В этой статье есть более подробное описание чистой архитектуры + MVVM https://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3
источник