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.


当前回答

在设计应用程序时,我避免使用单例。他们是很多人的典型选择,但我认为你可以在其他地方找到更优雅的解决方案。通常我做的是在CoreData中构建我的实体,然后把我的REST代码放在NSManagedObject类别中。例如,如果我想创建并POST一个新用户,我会这样做:

User* newUser = [User createInManagedObjectContext:managedObjectContext];
[newUser postOnSuccess:^(...) { ... } onFailure:^(...) { ... }];

我使用RESTKit进行对象映射,并在启动时初始化它。我发现通过单例路由您的所有调用是浪费时间,并添加了许多不需要的样板文件。

在NSManagedObject + Extensions.m:

+ (instancetype)createInContext:(NSManagedObjectContext*)context
{
    NSAssert(context.persistentStoreCoordinator.managedObjectModel.entitiesByName[[self entityName]] != nil, @"Entity with name %@ not found in model. Is your class name the same as your entity name?", [self entityName]);
    return [NSEntityDescription insertNewObjectForEntityForName:[self entityName] inManagedObjectContext:context];
}

在NSManagedObject + Networking.m:

- (void)getOnSuccess:(RESTSuccess)onSuccess onFailure:(RESTFailure)onFailure blockInput:(BOOL)blockInput
{
    [[RKObjectManager sharedManager] getObject:self path:nil parameters:nil success:onSuccess failure:onFailure];
    [self handleInputBlocking:blockInput];
}

当可以通过类别扩展公共基类的功能时,为什么还要添加额外的helper类呢?

如果你对我的解决方案更详细的信息感兴趣,请告诉我。我很乐意分享。

其他回答

在移动软件工程中,应用最广泛的是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

这个问题已经有很多优秀而广泛的答案,但我觉得我必须提一下,因为没有人提过。

斯威夫特的Alamofire。https://github.com/Alamofire/Alamofire

它是由与AFNetworking相同的人创建的,但在设计时更直接地考虑了Swift。

在设计应用程序时,我避免使用单例。他们是很多人的典型选择,但我认为你可以在其他地方找到更优雅的解决方案。通常我做的是在CoreData中构建我的实体,然后把我的REST代码放在NSManagedObject类别中。例如,如果我想创建并POST一个新用户,我会这样做:

User* newUser = [User createInManagedObjectContext:managedObjectContext];
[newUser postOnSuccess:^(...) { ... } onFailure:^(...) { ... }];

我使用RESTKit进行对象映射,并在启动时初始化它。我发现通过单例路由您的所有调用是浪费时间,并添加了许多不需要的样板文件。

在NSManagedObject + Extensions.m:

+ (instancetype)createInContext:(NSManagedObjectContext*)context
{
    NSAssert(context.persistentStoreCoordinator.managedObjectModel.entitiesByName[[self entityName]] != nil, @"Entity with name %@ not found in model. Is your class name the same as your entity name?", [self entityName]);
    return [NSEntityDescription insertNewObjectForEntityForName:[self entityName] inManagedObjectContext:context];
}

在NSManagedObject + Networking.m:

- (void)getOnSuccess:(RESTSuccess)onSuccess onFailure:(RESTFailure)onFailure blockInput:(BOOL)blockInput
{
    [[RKObjectManager sharedManager] getObject:self path:nil parameters:nil success:onSuccess failure:onFailure];
    [self handleInputBlocking:blockInput];
}

当可以通过类别扩展公共基类的功能时,为什么还要添加额外的helper类呢?

如果你对我的解决方案更详细的信息感兴趣,请告诉我。我很乐意分享。

我们根据具体情况使用几种方法。对于大多数事情来说,AFNetworking是最简单和最健壮的方法,因为你可以设置标题,上传多部分数据,使用GET, POST, PUT和DELETE,还有一堆附加的UIKit类别,允许你从url设置图像。在一个有很多调用的复杂应用程序中,我们有时会将其抽象为我们自己的方便方法,就像这样:

-(void)makeRequestToUrl:(NSURL *)url withParameters:(NSDictionary *)parameters success:(void (^)(id responseObject))success failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;

有一些情况下,AFNetworking是不合适的,但是,如你正在创建一个框架或其他库组件,因为AFNetworking可能已经在另一个代码库。在这种情况下,你可以使用NSMutableURLRequest内联,如果你正在做一个单独的调用或抽象到一个请求/响应类。

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

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

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

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