如何在我的 iOS 应用程序中正确实现一个服务类? [英] How to properly implement a Services class into my iOS application?

查看:23
本文介绍了如何在我的 iOS 应用程序中正确实现一个服务类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前的头疼:实现一个模型类,专门用于对我的 rails 应用程序的服务调用.

My current head scratcher: implementing a model class specifically for service calls to my rails application.

场景如下:

  • 我有一个名为 Service 的类,它是 NSObject 的子类.
  • 实现文件定义了一些方法……让我们看看doSignUp.
  • 我正在使用 AFNetworking 与 api 通信.
  • 从我的 SignUpViewController,我创建了一个我的实例Service 类并调用 doSignUp
  • 该方法按预期工作,我收到了服务器的正确响应.
  • I have a class named Service that is a subclass of NSObject.
  • The implementation file has a few methods defined… lets look at doSignUp.
  • I am using AFNetworking to communicate with the api.
  • From my SignUpViewController, I create an instance of my Service class and call doSignUp
  • The method works, as expected and I receive the proper response from the server.

现在是我不完全理解的部分:

Now Comes the part I don't fully understand:

  • AFNetworking 为其服务调用使用块.
  • success 块中,我调用了一个名为handleSignUp(也在Service 类中)的辅助方法.这个方法本质上解析了 JSON,我从中创建了一个新的 User(NSObject 子类).handSignUp 方法然后返回 User 对象.
  • AFNetworking utilizes blocks for its service calls.
  • Inside the success block I call a helper method called handleSignUp (also in Service class). This method essentially parses the JSON and I create a new User (NSObject subclass) out of it. The handSignUp method then returns the User object.

此时我有一个新的 User 对象,我需要将该对象发送回我的 SignUpViewController... 我该怎么做?

At this point I have a new User object and I need to send that object back to my SignUpViewController... How can I do that?

  • 我是否应该尝试将该对象添加到 AppDelegate 并访问它来自 SignUpViewController?此解决方案可以访问各种全局属性,但什么时候 SignUpViewController知道什么时候访问它?
  • 我是否应该尝试添加对 SignUpViewController 的引用服务 类?这似乎适得其反......我可能会将方法 doSignUphandSignUp 添加到SignUpViewController.在我看来,我的 Service 类不应该知道任何其他 viewController.
  • Should I try to add that object to the AppDelegate and access it from the SignUpViewController? This solution could work to access various global properties but when would the SignUpViewController know when to access it?
  • Should I try to add a reference to the SignUpViewController in the Service class? That seems counter productive... I might as well add the method doSignUp and handSignUp to the SignUpViewController. It seems to me like my Service class should not be aware of any other viewControllers.

请参阅下面的代码示例:

See below for my code examples:

Service.h

//Service.h
#import <UIKit/UIKit.h>
#import "AFNetworking.h"
@interface Services : NSObject
- (void) doSignUp:(NSMutableDictionary*)params;
@end

服务.m

// Service.m
 #import "Services.h"
 #import "Config.h"
 @implementation Services

 - (void) doSignUp:(NSMutableDictionary*)params {
     NSURL *url = [NSURL URLWithString:@"http://MYURL.COM"];
     AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
     NSURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"signup.json" parameters:params];
     AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
                                    success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
         [self handleSignUp:JSON];
     } failure:nil];
     [operation start];
 }

 - (User*) handleSignUp:(NSMutableArray*)json {
     User * user = nil;
     if ([[json valueForKey:@"success"] isEqualToString:@"true"]) {
           // create user here ...
     }
     return user;
 }

SignUpViewController.h

SignUpViewController.h

#import "Service.h"
 @interface SignUpViewController : UIViewController {
     Service * service;
 }

 @property (nonatomic, strong) Service * service;

SignUpViewController.m

SignUpViewController.m

#import "SignUpViewController.h"
 @interface SignUpViewController ()
 @end

 @implementation SignUpViewController

 @synthesize service = __service;
 - (IBAction) initSignUp:(id)sender {
      // create params...
      [self.service doSignUp:params];
 }

同样,所有这些代码都做了它应该做的......我只需要知道它们应该如何通信.如何通知 SignUpViewController handleSignUp 已被调用并且新的 User 对象可用?

Again, all this code does what it is supposed to do... I just need to know how it should all communicate. How can I alert the SignUpViewController the handleSignUp has been called and a new User object is available?

感谢您的时间,安德烈

推荐答案

据我所知,你没有意识到这个过程的异步性质:实际上,由于网络或 IO 操作需要很长时间才能完成,我们倾向于更喜欢异步访问,我的意思是:调用者(视图控制器)通过服务调用 Web API 上的消息,然后停止等待响应.实际上,网络处理可以在不同的进程或线程或处理器的核心上完成.

As far as i can see you are not realizing the asynchronous nature of this process: actually since network or IO operations take a long time to complete we tend to prefer asynchronous access, i mean: the caller (View Controller) calls a message on the web API through the service and then STOPS WAITING FOR A RESPONSE. Actually the network processing could be done on a different process or thread or processor's core.

那么,当操作完成时,服务如何通知调用者?为此,我们必须使用委托绑定两个对象:我们创建了一个协议(它只是一个对象将响应的消息声明)并在我们的视图控制器中实现它,这样任何使用它的人都会确定哪些消息可用.

Now then, how can the caller BE NOTIFIED by the service when the operation completes? For this to happen we must bind the two objects using Delegation: we create a protocol (it's just a declaration of messages that an object will be responding to) and we implement it in our View Controller, that way whoever will be using it will know for sure what messages are available.

然后我们将在我们的服务中声明一个类型为 id 的委托,一旦操作完成就会调用该委托.

Then we will declare a delegate of type id in our service that will be called once the operations will be completed.

这几乎就像在服务类中导入您的 ViewController.h 并为服务提供一个指向视图控制器的指针,但以正确的方式完成(没有循环引用并遵守 SOLID 原则)

It's almost like importing your ViewController.h in the service class and giving the service a pointer to the view controller, but done in the right way (without circular references and respecting SOLID principles)

现在一些代码:

//service.h
@protocol RemoteApiProtocol <NSObject>
@required
-(void) UserLoggingIn;
-(void) UserLoggedIn:(User*)user;
-(void) UserLoginError:(NSError *)error;
@end

协议就像一个小接口,它是两个类/对象之间的契约.然后在您的服务中,您可以声明 field &协议的属性:

The protocol works like a small interface, it's a contract between two classes/objects. Then in your service you can declare field & property for the protocol:

//Service.h
#import <UIKit/UIKit.h>
#import "AFNetworking.h"
@interface Services : NSObject{
      __weak id<RemoteApiProtocol> delegate;
}

@property (nonatomic, assign) id<RemoteApiProtocol> delegate;

- (void) doSignUp:(NSMutableDictionary*)params;

@end

此时您在视图控制器中实现了协议,集成了您刚刚构建的合约.这样服务器就会知道委托总是能够响应协议消息.

At this point you implement the protocol in your view controller, integrating the contract you just build. This way the server will know that the delegate will always be able to respond to the protocol messages.

//SignUpViewController.h
#import "Service.h"
 @interface SignUpViewController : UIViewController <RemoteApiProtocol> {
     Service * service;
 }

 @property (nonatomic, strong) Service * service;

在实现协议后,您可以将视图控制器分配为服务器的委托,这样服务器在调用 apis 后将能够使用调用结果调用委托.为此,您需要实现服务将调用的协议消息:

After implementing the protocol you can assign your view controller as delegate for the server, this way the server, after calling the apis will be able to call the delegate with the result of the call. For this to happen you implement the protocols messages that will be called by the service:

//SignUpViewController.m
#import "SignUpViewController.h"

 @implementation SignUpViewController

 @synthesize service = __service;
 - (IBAction) initSignUp:(id)sender {
      //create the service with params
      //...

      //assign self as the delegate
      self.service.delegate = self;
      [self.service doSignUp:params];
 }

#pragma mark - RemoteApiProtocol
-(void) UserLoggingIn
{
      //login started, 
      //you can show a spinner or animation here
}
-(void) UserLoggedIn:(User*)user
{
      //user logged in , do your stuff here
}
-(void) UserLoginError:(NSError *)error
{
      NSLog(@"error: %@",error);
}

@end

最后,在调用成功和错误块中的 apis 之后,调用服务中的消息:

And finally you call the messages in your service, after calling the apis in the success and error block:

// Service.m
 #import "Services.h"
 #import "Config.h"
 @implementation Services

 - (void) doSignUp:(NSMutableDictionary*)params {
     NSURL *url = [NSURL URLWithString:@"http://MYURL.COM"];
     AFHTTPClient *httpClient = [[AFHTTPClient alloc] initWithBaseURL:url];
     NSURLRequest *request = [httpClient requestWithMethod:@"POST" path:@"signup.json" parameters:params];
     AFJSONRequestOperation *operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
                                    success:^(NSURLRequest *request, NSHTTPURLResponse *response, id JSON) {
         [self handleSignUp:JSON];
     } failure:nil];


     //Signaling the start of the signup operation to the delegate
     if(self.delegate){
          [self.delegate UserLoggingIn];
     }

     [operation start];
 }

 - (User*) handleSignUp:(NSMutableArray*)json {
     User * user = nil;
     if ([[json valueForKey:@"success"] isEqualToString:@"true"]) {
           // create user here ...
           //call the delegate (view controller) passing the user
           if(self.delegate){
               [self.delegate UserLoggedIn:user];
           }
     }else{
           //error handling
           if(self.delegate){
               //NSError *error = ...
               //[self.delegate UserLoginError:error];
           }
     }


     //return user;
 }
@end

这篇关于如何在我的 iOS 应用程序中正确实现一个服务类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆