I'm an iOS developer with some experience and this question is really interesting to me. I saw a lot of different resources and materials on this topic, but nevertheless I'm still confused. What is the best architecture for an iOS networked application? I mean basic abstract framework, patterns, which will fit every networking application whether it is a small app which only have a few server requests or a complex REST client. Apple recommends to use MVC as a basic architectural approach for all iOS applications, but neither MVC nor the more modern MVVM patterns explain where to put network logic code and how to organize it in general. Do I need to develop something like MVCS(S for Service) and in this Service layer put all API requests and other networking logic, which in perspective may be really complex? After doing some research I found two basic approaches for this. Here it was recommended to create a separate class for every network request to web-service API (like LoginRequest class or PostCommentRequest class and so on) which all inherits from the base request abstract class AbstractBaseRequest and in addition to create some global network manager which encapsulates common networking code and other preferences (it may be AFNetworking customisation or RestKit tuning, if the we have complex object mappings and persistence, or even an own network communication implementation with standard API). But this approach seems an overhead for me. Another approach is to have some singleton API dispatcher or manager class as in the first approach, but not to create classes for every request and instead to encapsulate every request as an instance public method of this manager class like: fetchContacts, loginUser methods, etc. So, what is the best and correct way? Are there other interesting approaches I don't know yet? And should I create another layer for all this networking stuff like Service, or NetworkProvider layer or whatever on top of my MVC architecture, or this layer should be integrated (injected) into existing MVC layers e.g. Model? I know there exists beautiful approaches, or how then such mobile monsters like Facebook client or LinkedIn client deal with exponentially growing complexity of networking logic? I know there are no exact and formal answer to the problem. The goal of this question is to collect the most interesting approaches from experienced iOS developers. The best suggested approach will be marked as accepted and awarded with a reputation bounty, others will be upvoted. It is mostly a theoretical and research question. I want to understand basic, abstract and correct architectural approach for networking applications in iOS. I hope for detailed explanation from experienced developers.


当前回答

因为所有iOS应用程序都是不同的,所以我认为这里有不同的方法可以考虑,但我通常是这样做的: 创建一个中央管理器(单例)类来处理所有API请求(通常命名为apiccommunicator),每个实例方法都是一个API调用。有一个中心(非公共)方法:

-(RACSignal *)sendGetToServerToSubPath:(NSString *)path withParameters:(NSDictionary *)params;

For the record, I use 2 major libraries/frameworks, ReactiveCocoa and AFNetworking. ReactiveCocoa handles async networking responses perfectly, you can do (sendNext:, sendError:, etc.). This method calls the API, gets the results and sends them through RAC in 'raw' format (like NSArray what AFNetworking returns). Then a method like getStuffList: which called the above method subscribes to it's signal, parses the raw data into objects (with something like Motis) and sends the objects one by one to the caller (getStuffList: and similar methods also return a signal that the controller can subscribe to). The subscribed controller receives the objects by subscribeNext:'s block and handles them. I tried many ways in different apps but this one worked the best out of all so I've been using this in a few apps recently, it fits both small and big projects and it's easy to extend and maintain if something needs to be modified. Hope this helps, I'd like to hear others' opinions about my approach and maybe how others think this could be maybe improved.

其他回答

试试https://github.com/kevin0571/STNetTaskQueue

在分开的类中创建API请求。

STNetTaskQueue将处理线程和委托/回调。

可针对不同协议进行扩展。

根据这个问题的目的,我想描述一下我们的架构方法。

体系结构方法

我们通用的iOS应用的架构基于以下模式:服务层、MVVM、UI数据绑定、依赖注入;函数式响应式编程范式。

我们可以将一个典型的面向消费者的应用程序划分为以下逻辑层:

组装 模型 服务 存储 经理 协调员 用户界面 基础设施

组装层是应用程序的引导点。它包含一个依赖注入容器和应用程序对象及其依赖项的声明。这一层还可能包含应用程序的配置(url,第三方服务密钥等)。为此,我们使用了Typhoon库。

模型层包含域模型类、验证、映射。我们使用Mantle库来映射我们的模型:它支持序列化/反序列化到JSON格式和NSManagedObject模型。对于模型的验证和表单表示,我们使用FXForms和FXModelValidation库。

服务层声明了用于与外部系统交互的服务,以便发送或接收在域模型中表示的数据。因此,通常我们有用于与服务器api(每个实体)通信的服务、消息传递服务(如PubNub)、存储服务(如Amazon S3)等。基本上,服务包装SDK(例如PubNub SDK)提供的对象或实现它们自己的通信逻辑。对于一般的网络,我们使用AFNetworking库。

存储层的目的是组织设备上的本地数据存储。为此我们使用Core Data或Realm(两者都有优缺点,使用哪个取决于具体的规格)。对于CoreData设置,我们使用MDMCoreData库和一堆类-存储-(类似于服务),它们为每个实体提供对本地存储的访问。对于Realm,我们只是使用类似的存储来访问本地存储。

管理层是我们的抽象/包装器所在的地方。

经理角色可以是:

凭据管理器及其不同的实现(keychain, NSDefaults,…) 当前会话管理器,知道如何保持和提供当前用户会话 捕获管道,提供对媒体设备的访问(视频录制,音频,拍照) BLE管理器,提供对蓝牙服务和外围设备的访问 地理位置管理器 ...

因此,管理器的角色可以是任何实现应用程序工作所需的特定方面或关注点的逻辑的对象。

我们尽量避免singleton,但是如果需要的话,这一层是他们居住的地方。

协调器层提供依赖于其他层(服务、存储、模型)对象的对象,以便将它们的逻辑组合成特定模块(功能、屏幕、用户故事或用户体验)所需的一个工作序列。它通常链接异步操作,并知道如何对它们的成功和失败情况作出反应。作为一个例子,您可以想象一个消息传递特性和对应的MessagingCoordinator对象。处理发送消息操作可能是这样的:

验证消息(模型层) 本地保存消息(消息存储) 上传消息附件(amazon s3服务) 更新消息状态和附件url并在本地保存消息(消息存储) 将消息序列化为JSON格式(模型层) 向PubNub发布消息(PubNub服务) 更新消息状态和属性并将其保存在本地(消息存储)

在上述每一个步骤中,都会相应地处理一个错误。

UI层由以下子层组成:

视图模型 视图控制器 视图

为了避免大量的视图控制器,我们使用MVVM模式,并在视图模型中实现UI表示所需的逻辑。ViewModel通常有协调器和管理器作为依赖项。viewcontroller和某些类型的视图(例如表视图单元格)使用的viewmodel。视图控制器和视图模型之间的粘合剂是数据绑定和命令模式。为了使它有可能有胶水,我们使用ReactiveCocoa库。

我们还使用ReactiveCocoa及其RACSignal概念作为所有协调器、服务和存储方法的接口和返回值类型。这允许我们链式操作,并行或串行运行它们,以及ReactiveCocoa提供的许多其他有用的东西。

我们尝试以声明式的方式实现UI行为。数据绑定和自动布局有助于实现这一目标。

基础设施层包含应用程序工作所需的所有帮助程序、扩展和实用程序。


这种方法对我们和我们通常构建的那些类型的应用都很有效。但你应该明白,这只是一种主观的方法,应该根据具体的团队目的进行调整/改变。

希望这对你有所帮助!

你也可以在这篇文章中找到更多关于iOS开发过程的信息

因为所有iOS应用程序都是不同的,所以我认为这里有不同的方法可以考虑,但我通常是这样做的: 创建一个中央管理器(单例)类来处理所有API请求(通常命名为apiccommunicator),每个实例方法都是一个API调用。有一个中心(非公共)方法:

-(RACSignal *)sendGetToServerToSubPath:(NSString *)path withParameters:(NSDictionary *)params;

For the record, I use 2 major libraries/frameworks, ReactiveCocoa and AFNetworking. ReactiveCocoa handles async networking responses perfectly, you can do (sendNext:, sendError:, etc.). This method calls the API, gets the results and sends them through RAC in 'raw' format (like NSArray what AFNetworking returns). Then a method like getStuffList: which called the above method subscribes to it's signal, parses the raw data into objects (with something like Motis) and sends the objects one by one to the caller (getStuffList: and similar methods also return a signal that the controller can subscribe to). The subscribed controller receives the objects by subscribeNext:'s block and handles them. I tried many ways in different apps but this one worked the best out of all so I've been using this in a few apps recently, it fits both small and big projects and it's easy to extend and maintain if something needs to be modified. Hope this helps, I'd like to hear others' opinions about my approach and maybe how others think this could be maybe improved.

在移动软件工程中,应用最广泛的是Clean Architecture + MVVM和Redux模式。

Clean Architecture + MVVM由3层组成: 域、表示、数据层。 表示层和数据存储库层依赖于域层:

Presentation Layer -> Domain Layer <- Data Repositories Layer

表示层由视图模型和视图(MVVM)组成:

Presentation Layer (MVVM) = ViewModels + Views
Domain Layer = Entities + Use Cases + Repositories Interfaces
Data Repositories Layer = Repositories Implementations + API (Network) + Persistence DB

在本文中,将对Clean Architecture + MVVM进行更详细的描述 https://tech.olx.com/clean-architecture-and-mvvm-on-ios-c9d167d9f5b3

To my mind all software architecture is driven by need. If this is for learning or personal purposes, then decide the primary goal and have that drive the architecture. If this is a work for hire, then the business need is paramount. The trick is to not let shiny things distract you from the real needs. I find this hard to do. There are always new shiny things appearing in this business and lots of them are not useful, but you can't always tell that up front. Focus on the need and be willing to abandon bad choices if you can.

For example, I recently did a quick prototype of a photo sharing app for a local business. Since the business need was to do something quick and dirty, the architecture ended up being some iOS code to pop up a camera and some network code attached to a Send Button that uploaded the image to a S3 store and wrote to a SimpleDB domain. The code was trivial and the cost minimal and the client has an scalable photo collection accessible over the web with REST calls. Cheap and dumb, the app had lots of flaws and would lock the UI on occasion, but it would be a waste to do more for a prototype and it allows them to deploy to their staff and generate thousands of test images easily without performance or scalability concerns. Crappy architecture, but it fit the need and cost perfectly.

Another project involved implementing a local secure database which synchronizes with the company system in the background when the network is available. I created a background synchronizer that used RestKit as it seemed to have everything I needed. But I had to write so much custom code for RestKit to deal with idiosyncratic JSON that I could have done it all quicker by writing my own JSON to CoreData transformations. However, the customer wanted to bring this app in house and I felt that RestKit would be similar to the frameworks that they used on other platforms. I waiting to see if that was a good decision.

Again, the issue to me is to focus on the need and let that determine the architecture. I try like hell to avoid using third party packages as they bring costs that only appears after the app has been in the field for a while. I try to avoid making class hierarchies as they rarely pay off. If I can write something in a reasonable period of time instead of adopting a package that doesn't fit perfectly, then I do it. My code is well structured for debugging and appropriately commented, but third party packages rarely are. With that said, I find AF Networking too useful to ignore and well structured, well commented, and maintained and I use it a lot! RestKit covers a lot of common cases, but I feel like I've been in a fight when I use it, and most of the data sources I encounter are full of quirks and issues that are best handled with custom code. In my last few apps I just use the built in JSON converters and write a few utility methods.

One pattern I always use is to get the network calls off the main thread. The last 4-5 apps I've done set up a background timer task using dispatch_source_create that wakes up every so often and does network tasks as needed. You need to do some thread safety work and make sure that UI modifying code gets sent to the main thread. It also helps to do your onboarding/initialization in such a way that the user doesn't feel burdened or delayed. So far this has been working rather well. I suggest looking into these things.

Finally, I think that as we work more and as the OS evolves, we tend to develop better solutions. It has taken me years to get over my belief that I have to follow patterns and designs that other people claim are mandatory. If I am working in a context where that is part of the local religion, ahem, I mean the departmental best engineering practices, then I follow the customs to the letter, that's what they are paying me for. But I rarely find that following older designs and patterns is the optimal solution. I always try to look at the solution through the prism of the business needs and build the architecture to match it and keep things as simple as they can be. When I feel like there isn't enough there, but everything works correctly, then I'm on the right track.